728x90
CS
TCP/UDP
TCP
- 연결 지향형 서비스(reliable service)와 신뢰적 데이터 전송 서비스(data integrity)를 포함한다.
- Reliable Service
- TCP는 메시지 전송 전에 클라이언트와 서버가 서로 전송 제어 정보를 교환하도록 한다. 즉, 패킷이 전송될것을 미리 알려준다.
- Data integrity
- TCP는 데이터를 오류 없이 올바른 순서로 전달하는 것을 보장한다.
- Congestion control(혼잡제어)
- TCP의 congestion control은 네트워크가 혼잡상태에 이르면 프로세스의 속도를 낮춘다.
- 즉, 프로세스가 우선이 아니라 네트워크의 안정성 향상을 우선한다.
- Flow control(흐름제어)
- TCP는 receiver의 buffer가 꽉 차서 데이터가 손실되지 않도록 sender의 전송을 관리한다.
- TCP는 최대한 오류 없는 신뢰성 있는 전송을 위해 많은 기능을 지원하며, 이에 따라 속도가 UDP에 비해 불리할 수 있다.
- 안정적이고 정확한 패킷 전달을 보장한다는 특징이 있다.
UDP
- 최소의 서비스 모델을 가지는 간단한 프로토콜이다.
- 비연결형임으로 핸드셰이킹을 하지 않는다.
- 비 신뢰적인 서비스이므로 데이터가 손실될 수 있다. UDP는 flow control을 하지 않으므로 프로세스는 원하는 속도로 하위 계층으로 보낼 수 있다. 그 외 올바른 패킷 전송에 필요한 여러가지 제어를 전부 하지 않는다.
- 데이터그램을 생성하며, 데이터 전송의 신뢰성을 보장하지 않는다. 비연결형이고, 데이터를 보내고 신경쓰지 않는다. 재전송도 없다.
- 그래서 TCP보다 비교적 빠르다. 연결 상태를 만들지 않으므로 유지할 필요도 없다. 또한 패킷이 순서대로 오는 것을 보장하지 않기 때문에 수신자가 헤더를 보고 조합해야 한다.
Nagle 알고리즘
- TCP 네트워크에서, 데이터는 OSI레이어를 거치면서 몇 겹의 헤더로 캡슐화되어 목적지로 보내진다. 또한, 패킷 전송에는 비용이 따른다.
- 이런 경우 데이터가 적다면 보내는 효율이 떨어지는데, 적은 데이터를 가진 패킷을 여러번 보내는 것보다는 많은 데이터를 가진 패킷을 한번에 보내는 것이 효율이 좋다.
- 이럴 경우, 상대가 받을 수 있는 사이즈(window size)가 충분하다면 크기가 작은 패킷을 모아서 보내는 것을 Nagle 알고리즘이라고 한다.
- 전송의 효율이 증가하지만, 즉각적인 반응이 필요한 네트워크 게임 등에는 적합하지 않다.
- rax register
- rax 레지스터는 x86-64 아키텍처에서 사용되는 64비트 범용 레지스터 중 하나이다.
주요 기능과 특징
- 범용레지스터
- 산술 연산, 논리 연산, 데이터 이동 등에 사용된다.
- 특정 용도
- 특정 명령어에서 결과를 저장하는 용도로 사용된다.
- 함수 호출 규약
- 많은 함수 호출 규약(ABI)에서 ‘rax’ 레지스터는 함수의 반환 값을 저장하는 데 사용된다. 만약 함수가 정수 값을 반환하는 경우 그 값은 ‘rax’ 레지스터에 저장된다.
32 bit OS VS 64 bit OS
- 32비트 운영 체제와 64비트 운영 체제는 주로 처리 능력, 메모리 주소 지정, 성능 및 호환성 측면에서 차이가 있다.
데이터 버스와 메모리 주소 지정
- 32비트 OS
- 주소 버스 크기 : 32비트 주소 버스 사용, 이론적으로 최대 4GB 지원
- 데이터 버스 크기 : 32비트 데이터 버스를 사용하여 한 번에 32비트(4바이트) 데이터를 전송할 수 있다.
- 메모리 제한 : 실제로 하드웨어 및 운영 체제의 예약된 공간 때문에 일반적으로 3GB에서 3.5GB정도의 RAM만 활용 가능하다.
- 64비트 OS
- 주소 버스 크기 : 64비트 주소 버스 사용 이론적으로 최대 16엑사바이트 RAM 지원
- 데이터 버스 크기 : 65비트 데이터 버스를 사용하여 한 번에 64비트 데이터를 전송 가능
- 메모리 제한 : 실제로는 현재의 하드웨어 및 운영 체제 구현에서 수 페타바이트 정도까지 지원 가능
성능 및 처리 능력
- 32비트 OS
- 레지스터 크기 : 32비트 레지스터
- 프로세스당 메모리 : 하나의 프로세스가 최대 4GB의 메모리만 사용할 수 있다.
- 연산 성능 : 32비트 정수 및 부동 소수점 연산을 기본으로 한다.
- 64비트 OS
- 레지스터 크기 : 64비트 레지스터
- 프로세스당 메모리 : 하나의 프로세스가 사용할 수 있는 메모리의 상한선이 매우 높어져 메모리 집약적인 응용 프로그램이 더 효율적으로 동작한다.
- 연산 성능 : 64비트 정수 및 부동 소수점 연산을 기본으로 하여 더 빠른 연산이 가능하다.
- 메모리 풀(Memory pool)
- 메모리 풀은 고정된 크기의 블록을 할당하여 malloc이나 new 연산자와 유사한 메모리 동적 할당을 가능하게 해준다. malloc이나 new 연산자 같은 기능들은 다양한 블록사이즈 때문에 단편화를 유발시키고, 파편화된 메모리들은 퍼포먼스 때문에 실시간 시스템에서 사용할 수 없게 된다.
- 좀 더 효율적인 방법은 memory pool이라고 불리는 동일한 사이즈의 메모리 블록들을 미리 할당 해 놓는 것이다. 그러면 응용 프로그램들은 실행 시간에 핸들에 의해서 표현되는 블록들을 할당하고, 접근하고, 해제할 수 있다.
- 프로그래머가 할 수 있는 외부, 내부 단편화의 해결법이다. 프로그래머가 직접 메모리를 관리할 수 있는 특정 크기의 풀(pool)을 만들어서 그 풀에서 메모리를 가져오고, 사용이 끝나면 돌려준다.
장점
- 단편화를 완화할 수 있다. 할당/해제가 빈번할 때 new/delete를 통해 새로 할당/해제할 필요가 없이 풀에서 가져오고, 반납하면 되므로 비용이 크게 감소한다.
단점
- 메모리 풀은 프로그래머가 직접 메모리를 0부터 100까지 관리하겠다고 선언하는 것이나 다름없다. 즉, 모든 메모리 문제의 책임은 프로그래머가 가지게 된다.
- 사용하지 않을 때에도 풀을 유지해야 하므로 메모리 낭비가 생긴다.
페이징(Paging)
- 페이징이란 가상 메모리를 페이지로 나누어 다루는 기법이다.
- 페이지(가상 메모리 나눔의 단위)와 프로임(물리 메모리 나눔의 단위)은 1:1 대응되며 (가상 메모리의 주소값과 물리 메모리의 주소값은 다르므로, 자상 메모리 주소를 기반으로 물리 메모리 주소를 찾아가서 데이터를 가져온다.), 이로 인해 물리적으로 연속적이지 않아도 가상 메모리에서 연속된 메모리를 할당할 수 있기 때문에 외부단편화를 완화한다.
C++
참조자
- C언어에서는 어떠한 변수를 가리키고 싶을 때 반드시 포인트를 사용해야 했다. C++에서는 다른 변수나 상수를 가리키는 방법으로 또 다른 방식을 제공하는데, 이를 바로 참조자(레퍼런스 - reference)라고 부른다.
- 참조자를 정하는 방법은 가리키고자 하는 타입 뒤에 &를 붙이면 된다. 위처럼 int 형 변수의 참조자를 만들고 싶을 때는 int& , double 의 참조자를 만드려면 double& 로 하면 된다. 심지어 int* 와 같은 포인터 타입의 참조자를 만드려면 int*&로 쓰면 된다.
- 참조자 선언은 또 다른 이름 이라고 컴파일러에게 알려주는 것이다. 따라서 참조자는 어떠한 작업을 수행하든 참조된 원본에 그 작업을 하는 것과 마찬가지이다.
- 참조자는 포인터와 상당히 유사한 개념이지만 몇 가지 차이점이 있다.
- 레퍼런스는 반드시 처음에 누구의 별명이 될 것인지 지정해야 한다 따라서 아래와 같은 문장은 불가능하다. 반면 포인터의 경우 전혀 문제가 없는 코드이다.
- int& another_a; // X int* p; // O
- 레퍼런스가 한 번 별명이 되면 절대 다른 이의 별명이 될 수 없다.
- 한 번 어떤 변수의 참조자가 되버린다면, 더 이상 다른 변수를 참조 할 수 없게 된다.
- 레퍼런스는 메모리 상에 존재하지 않을 수도 있다.
- 이의 경우 another_a 가 쓰이는 자리는 모두 a 로 바꿔치기 하면 되기 때문에 레퍼런스가 메모리 상에 존재하지 않게 된다.
- int a = 10; int &another_a = a;
상수에 대한 참조자
- 상수 값 자체는 리터럴 이기 떄문에 많일 위와 같이 레퍼런스로 참조한다면 리터럴의 값을 바꾸는 말도 안되는 행위가 가능하기 때문에 따라서 C++ 문법 상 상수 리터럴을 일반적인 레퍼런스가 참조하는 것은 불가능하게 되어 있다.
- 물론 그 대신에
- const int &ref = 4;
- 상수 참조자로 선언한다면 리터럴도 참조할 수 있다.
레퍼런스의 배열과 배열의 레퍼런스
- 컴파일에서 레퍼런스의 배열을 불법(illegal)이라고 한다. C++ 규정에서 언어 차원에서 불가능하다고 나와 있다.
- C++ 상에서 배열이 어떻게 처리되는 지 생각해본다면, 문법 상 배열의 이름은 (arr ) 첫 번째 원소의 주소값으로 변환이 될 수 있어야 한다. 이 때문에 arr[1] 과 같은 문장이 *(arr + 1) 로 바뀌어서 처리될 수 있다.
- 주소값이 존재한다라는 의미는 해당 원소가 메모리 상에서 존재한다 라는 의미와 같다. 하지만 레퍼런스는 특별한 경우가 아닌 이상 메모리 상에서 공간을 차지하지 않는다. 따라서 이러한 모순 때문에 레퍼런스들의 배열을 정의하는 것은 언어 차원에서 금지가 되어 있다.
- 그와 반대인 배열들의 레퍼런스가 불가능 한 것은 아니다.
레퍼런스를 리턴하는 함수
- 지역변수의 레퍼런스를 리턴해서 컴파일 한다면 경고가 나오고 실제로 실행해보면 런타임 오류가 발생한다.
- 이와 같이 레퍼런스는 있는데 원래 참조 하던 것이 사라진 레퍼런스를 댕글링 레퍼런스(Dangling reference)라고 부른다.
- 따라서 레퍼런스를 리턴하는 함수에서 지역 변수의 레퍼런스를 리턴하지 않도록 조심해야 한다.
- 참조자를 리턴하는 경우 C언어에서 엄청나게 큰 구조체가 있을 때 해당 구조체 변수를 그냥 리턴하면 전체 복사가 발생해야 해서 시간이 오래 걸리지만, 해당 구조체를 가리키는 포인터를 리턴한다면 그냥 포인터 주소 한 번 복사로 매우 빠르게 끝난다. 마찬가지로 레퍼런스를 리턴하게 된다면 레퍼런스가 참조하는 타입의 크기와 상관 없이 딱 한 번의 주소값 복사로 전달이 끝나게 된다.
참조자가 아닌 값을 리턴하는 함수를 참조자로 받기
- 원칙상 함수의 리턴 값은 해당 문장이 끝나면 소멸되는 것이 정상이다. 하지만 예외적으로 상수 레퍼런스로 리턴 값을 받게 되면 해당 리턴 값의 생명이 연장된다. 그리고 그 연장되는 기간은 레퍼런스가 사라질 때 까지이다.
728x90
'Study > TIL(Today I Learned)' 카테고리의 다른 글
24.11.14 CS (0) | 2024.11.14 |
---|---|
24.11.13 CS (1) | 2024.11.13 |
24.11.11 CS (0) | 2024.11.11 |
24.11.07 CS, VV (2) | 2024.11.08 |
24.11.04 VV. 장애물, UI 구현, 점수 구현 (0) | 2024.11.04 |