기술을 논의할 때 그 진화 과정을 이해하지 못하고 현재에만 집중한다면 절대 그 기술을 이해할 수 없을 것임. 프로그래머의 눈에 보이는 CPU어떤 복잡한 대규모 응용 프로그램이든 간에 결국 컴파일러로 하나하나 간단한 기계 명령어로 변환함.본질적으로 CPU 입장에서 프로그램에 따른 차이가 없음.단지 명령어가 많은지 적은지의 차이만 있을 뿐임.CPU는 단순하게 실행파일에 적힌 명령어가 메모리에 적재되면 그걸 읽어 실행하기만 함. CPU의 능력 범위: 명령어 집합CPU 유형에 따라 고유한 능력 범위를 가지고 있음.이를 명령어 집합(instruction set architecture) 라고 함.명령어 집합에는 여러 가지 명령어가 포함됨.명령어 집합은 프로그래머가 프로그래밍에 사용함.서로 다른 형태의 CPU는 다른..
레시피와 코드, 볶음 요리와 스레드요리사는 레시피에 따라 특정 작업을 실행하여 특정한 요리를 만듦.ex) 레시피에 따라 돼지고기를 볶으면 돼지 두루치기 스레드가 됨.CPU는 기계 명령어에 따라 프로세스와 스레드를 실행함.운영체제 입장에서, CPU가 사용자 상태에서 실행하는 명령어는 모두 특정 스레드에 속해있음.요리사 수는 CPU 코어 수에 비유할 수 있음.일정 시간 동안 볶을 수 있는 요리 수는 스레드 수에 비유할 수 있음.‘요리사 수’가 ‘동시에 얼마나 많은 요리를 할 수 있는지’ 여부와 관련이 없음.CPU 코어 수와 스레드 수 사이에는 어떤 필연 관계도 없음.CPU는 하드웨어, 스레드는 소프트웨어 개념(실행 흐름이자 작업)임.즉, 단일 코어 시스템에서도 많은 스레드를 생성할 수 있음. (메모리가 충분..
const unsigned arraySize = 10000;int data[arraySize];long long sum = 0;for (unsigned i = 0; i = 128) { sum += data[c]; } }}만약 배열요소가 정렬된 상태라면 약 2.8초 만에 실행이 완료되지만, 배열 요소가 임의로 배치되면 실행 시간이 무려 약 7.5초에 달함.리눅스의 perf 도구를 이용하여 프로그램 실행 상태에 대한 초기 단계를 분석해서 문제를 확인해 볼 수 있음.perf 를 이용하면 CPU와 관련된 모든 중요한 정보를 확인할 수 있음.branch-misses 항목이 있는데, 정렬된 배열을 이용한 프로그램에서 예측 실패율은 0.02%에 불과하지만, 정렬되지 않은 배열을 이용한 프로그램에서 최고 14...
컴퓨터 시스템이 2진법인 이유는 컴퓨터의 저수준 계층이 각각 켜고 끄는 스위치인 트랜지스터로 구성되어 있기 때문임.숫자 0과 양의 정수0이라는 개념을 표현하기 위해 위치 기수법을 사용하여 값과 숫자의 위치를 표현함.ex) 숫자 5를 2진법으로 표기하면 101(2) 임. → 1 x 2^2 + 0 x 2^1 + 1 x 2^0비트 k개를 사용하면 정수 2^k개를 나타낼 수 있음.ex) k가 8 비트이면, 표현 가능한 범위는 0~255 임. → 부호 없는 정수에 해당함.부호 있는 정수부호 없는 정수를 나타내려면 부호 있는 정수에서 표현 범위를 반으로 나누면 됨.ex) 4비트 부호 없는 정수 → 0~15부호 있는 정수는 1~7, 그리고 -8~-1 까지 표현할 수 있음.비트로 표현한다면, 최상위 비트를 정수 부호로..
컴퓨터의 CPU 사용률은 얼마인가?대부분의 CPU 사용률은 7~8% 정도로 매우 낮음.물론 게임, 영상 편집, 이미지 처리 같은 상황은 다르게 판단해야 함.이러한 상황이 아님에도 사용률이 항상 높다면 소프트웨어 버그이거나, 바이러스 감염 가능성을 고려해야 함.ex) 프로세스가 약 300개가 열려있는데, 이렇게 많은 프로세스는 기본적으로 아무 작업도 하지 않고 있음.특정 이벤트가 발생하여 자신을 깨우기를 기다리고 있음.즉, 그전 까지는 계속 대기 상태에 머무르게 됨.프로세스 관리와 스케줄링프로그램이 메모리에서 실행되면 프로세스 형태로 존재함.프로세스가 생성되면 운영 체제가 관리하고 스케줄링 함.프로세스에 우선순위를 할당하고, 우선순위에 따라 스케줄러(scheduler)가 스케줄링할 수 있도록 대기열을 통해..
위대한 발명트랜지스터는 한쪽에 전류를 흘려서 나머지 단자 두 개에 전류가 흐르거나 흐르지 못하게 할 수 있음.스위치와 동일함.프로그래머가 작성한 프로그램이 아무리 복잡해도 소프트웨어가 수행하는 최종적 기능은 이 트랜지스터의 간단한 개폐 작업으로 완성됨.논리곱, 논리합, 논리부정스위치 두 개를 동시에 켜야만 전류가 흐른다 → 논리곱스위치 둘 중 하나라도 켜있으면 전류가 흐른다 → 논리합스위치를 닫아야만 전류가 흐름 → 논리부정이러한 논리곱, 논리합, 논리부정 게이트로 모든 논리 함수를 표현할 수 있음.논리적 완전성(logical completness) 라고 함.이 논리 게이트외에 어떠한 다른 형태의 논리 게이트 회로가 필요가 없음.위 세 논리 게이트가 논리적으로 완전하다고 간주함.연산 능력은 어디에서 나올..
현재 기준, 성능이 가장 좋은 SSD 제원을 확인해보면 순차 읽기 속도가 최대 7.5GB/s 임.현재 5세대 DDR 메모리 최대 대역폭은 60GB/s 임.즉, SSD 속도로 비교해보면 SSD 를 메모리로 사용하면 컴퓨터 속도가 현재보다 약 10분의 1 수준으로 느려짐.메모리 읽기/쓰기 vs 디스크 읽기/쓰기메모리의 주소 지정 단위는 바이트임.각 바이트마다 메모리 주소가 부여되어 있음.CPU가 이 주소를 이용하여 해당 내용을 직접 접근할 수 있음.SSD는 조각 단위로 데이터를 관리함.이 조각 크기는 매우 다양함.CPU가 파일의 특정 바이트에 직접 접근할 수 있는 방법이 없음.즉, 바이트 단위 주소 지정이 지원되지 않음.즉, CPU는 SSD 또는 디스크에서 직접 프로그램을 실행할 수 없음.가상 메모리의 제한..
지역 변수의 포인터 반환하기int* func(){ int a = 2; return &a;}void main(){ int* p = func(); *p = 20;}지역 변수 a가 func 함수의 스택 프레임에 위치함.func 함수의 실행이 끝나면 해당 스택 프레임도 없어짐.즉, main 함수의 func 함수를 호출한 후 얻은 포인터는 이미 없는 변수를 가리킴.만약 위 상황에서, 추가적으로 foo 와 같은 함수가 호출되면 포인터 p의 내용을 foo 함수의 스택 프레임이 덮어 쓰게됨.혹은, 포인터 p가 가리키는 값을 수정하면 실제로 foo 함수의 스택 프레임이 파괴됨.포인터 연산의 잘못된 이해포인터 연산에 1을 더하는 것은 1바이트만 이동하는 것이 아님.단위 한 개만큼 이동함.ex) int..
메모리 풀 vs 범용 메모리 할당자범용 메모리 할당자인 malloc 은 표준 라이브러리의 일부임.설계 및 구현이 비교적 복잡함.메모리 풀은 응용 프로그램의 일부임.설계 및 구현이 비교적 간단함.특정 상황에서만 메모리 할당 성능을 최적화하기에 범용성이 매우 떨어짐.메모리 풀 기술의 원리한 번에 큰 메모리 조각을 요청하고 그 위에서 자체적으로 메모리 할당과 해제를 관리하는 방식임.표준 라이브러리와 운영 체제를 우회함.특정 사용 패턴에 따라 최적화도 가능함.ex) 서버에서 사용자 요청을 처리할 때마다 여러 종류의 객체를 생성해야 한다면, 자체 메모리 풀에서 미리 이 객체를 생성해 두는 것이 가능함.초간단 메모리 풀 구현ex) 서버 프로그래밍단 한 종류의 객체만 사용한다면, 미리 객체를 메모리로 생성하여 실제 ..
CPU 실행상태x86 CPU는 네 가지 특권 단계를 제공함.CPU의 여러 가지 동작 상태를 나타냄.숫자가 작을 수록 CPU의 특권은 커짐.여기서 특권은, 일부 명령어를 실행할 수 있는지를 나타냄.일반적으로 시스템은 CPU 특권 단계 0, 3 두 단계만 이용함.3단계는 사용자 상태(user mode), 0단계는 커널 상태(kernel mode) 라고 함.커널 상태와 사용자 상태CPU가 운영 체제의 코드를 실행할 때 바로 커널 상태에 놓임.커널 상태에서는 CPU가 모든 기계 명령어를 실행할 수 있고, 모든 주소 공간에 접근할 수 있음.제한 없이 하드웨어에 접근할 수 있음.프로그래머가 작성한 일반적인 코드를 CPU가 실행할 때는 사용자 상태에 해당함.특정 주소 공간에 절대 접근할 수 없음.이것이 바로 유명한 ..
여유 메모리 조각을 선택하는 방법최초 적합 방식매번 처음부터 탐색하다가 가장 먼저 발견된 요구 사항을 만족하는 항목을 반환first fit 방식이라고 함.다음 적합 방식메모리를 요청할 때 처음부터 검색하는 대신 적합한 여유 메모리 조각이 마지막으로 발견된 위치에서 시작함.최적 적합 방식사용 가능한 메모리 조각을 모두 찾은 후 그중 요구 사항을 만족하면서 크기가 가장 작은 조각을 반환함.메모리 할당머리 정보와 남아있는 할당 정보를 통해 내부 단편화를 최소화하여 메모리 할당할 수 있음.메모리 해제사용자가 메모리 해제 요청할 주소를 전달하면 해당 머리 정보를 통해 여유 메모리로 바꾸면 해제가 완료 됨.여유 메모리 조각을 효율적으로 병합메모리 조각 끝에 꼬리 정보를 추가함.메모리 조각을 일종의 암시적 양방향 연..
힙 영역이 필요한 이유특정 데이터를 여러 함수에 걸쳐 사용해야 한다면?전역 변수는 모든 모듈에 노출되어 있는데, 모든 모듈에 노출하고 싶지 않을 때가 있음.이때, 프로그래머가 직접 관리하는 특정 메모리 영역에 저장해야 함.메모리 수명 주기에 프로그래머가 완전히 직접 제어할 수 있는 매우 큰 메모리 영역이 필요함.이를 바로 힙 영역이라고 함.malloc 메모리 할당자 직접 구현하기c/c++ 언어에서 메모리의 도적 할당과 해제 요청은 모두 전문적으로 힙 영역에 메모리를 할당하고 해제하는 작은 프로그램에 전달되어야 함.이 프로그램은 malloc 메모리 할당자임.메모리 할당자 입장에서 적절한 크기의 메모리 영역을 제공하기만 하면 됨.할당자는 그 메모리 영역에 무엇을 저장할지까지는 신경 쓰지 않음.힙 영역은 사실..