10월, 2015의 게시물 표시

[Windows Via C/C++][13장] Page, Block, Region, Partition

Page와 Block과 Region, 그리고 Partition의 용어가 헷갈려서 정리를 해놓는다. Virtual Address Space  : Process가 사용할 수 있는 가상적인 주소 공간. Partion  : 프로세스의 가상 주소 공간을 분할시킨 것 (윈도우에서 가상 주소 공간은 4개로 분할된다 - NULL포인트 할당, 유저 모드, 64KB접근금지, 커널모드) Region  : VirtualAlloc을 통해 reserve혹은 commit된 가상 주소 공간. 혹은 연속된 free상태의 페이지들의 집합. Block  : 동일한 보호 특성을 가지고 동일한 형태의 물리적 저장소에 매핑된 연속된 페이지들의 집합 (동일한 보호 특성, 상태, 페이지 형태를 가진 인접하는 모든 페이지들의 집합) Page  : 가상 주소 공간을 일정한 크기로 나눈 것 (x86, x64에서 4KB, IA-64에서는 8KB이다..) 즉, 윈도우의 Virtual Address Space는 4개의 Partion으로 구분되고 각각의 Partion은 여러개의 Region으로 구분된다. 그리고 Region은 또 여러개의 Block으로 구분할 수 있고, 각각의 Block은 하나이상의 Page들로 이루어지게 된다.

fork와 vfork

fork는 새로운 프로세스를 만드는 리눅스 시스템 콜이다. fork로 인해 생성된 자식 프로세스와 부모 프로세스는 서로 별개의 메모리영역을 가진다. 하지만 자식프로세스가 생성될 때 아예 부모의 메모리를 copy하는 것은 아니고 실제로는 부모와 자식이 page를 공유하다가 부모,자식중 누군가가 특정 page에 대해 쓰기작업을 할 때 그 누군가를 위한 page의 copy가 발생한다.  그러면 부모 자식관계가 여러명이면 어떻게 될까? 그래도 똑같다. 커널 내부적으로 fork에 의해 맺어진 프로세스들 사이에 page의 공유에 대한 정보가 저장되있을테고 그 프로세스들중 한 명만 write를 하면 그 한 명을 위해 copy가 발생하고 이제 그 프로세스는 다른 page를 사용하게 되는 것이다. http://unix.stackexchange.com/questions/58145/how-does-copy-on-write-in-fork-handle-multiple-fork vfork는 예전에 fork가 내부적으로 COW를 사용하지 않을 때를 위해서 만들어졌다고 한다. (vfork는 vfork + execve 를 위한 fork의 최적화 버전이라고 한다.) https://wiki.kldp.org/HOWTO/html/Secure-Programs-HOWTO/avoid-vfork.html vfork는 마치 clone처럼 부모와 자식이 같은 메모리영역을 공유한다. (하지만 스택조차도 공유한다.) 하지만 vfork를 하게 되면 부모 process는 자식 process가 종료되거나 exec* 함수를 호출할 때 다시 수행이 재개된다. 이 때 주의할 점이 자식 process가 return혹은 exit함수를 통해 종료되서는 안되고, 무조건 _exit함수를 통해 종료되어야 한다는 점이다. 왜냐하면 vfork는 자식process가 부모process의 스택조차도 그대로 사용하기 때문에 자식process가 스택을 어지럽히면 부모process의 실행이 이상할 수 있기 때문이다. r

Data Alignment

CPU는 byte단위로 data를 읽는 것이 아니라 word단위로 data를 메모리에서 읽어들인다.  예를 들어 x86의 경우 32비트(4바이트)단위로 data를 읽어들이는데 이는 즉 0x0에서 0x3까지 4바이트를 읽어들이는 것은 한 번에 데이터를 읽어들일 수 있지만 0x1부터 0x4까지 4바이트를 읽어들이려면 0x0 ~ 0x3 , 0x4 ~ 0x7 이렇게 총 2 번 메모리를 읽어들여야 한다. 이러한 데이터를 비정렬 데이터라고 하는데 만약 비정렬 데이터를 들어들이려고 할 때 cpu의 동작은 cpu마다 다르다. 예를 들어, x86이나 x64같은 경우 cpu는 기본적으로 메모리 상에서 비정렬된 데이터에 대한 읽기 작업을 2개의 정렬된 위치에서의 읽기 작업으로 전환해서 수행한다. 즉 성능이 매우 안좋아지는 것이다. 하지만 예외가 발생하지는 않는다. 그러나 IA-64같은 경우는 비정렬 데이터에 접근하려고 하면 비정렬 예외가 발생하고 OS가 그 예외를 자동으로 처리해주거나 소프트웨어에 예외가 전달되게 된다. 그러면 x86기반에서 visual C++을 이용해 구조체를 사용하면 double같은 경우 8-byte로 alignment가 된다. 이는 왜 그런걸까? double(8-byte type)을 4-byte alignment하든 8-byte alignment하든 cpu는 2번 메모리에서 읽어들여야하는데 말이다. 그 이유는 바로 캐시라인 때문이다. 캐시라인의 크기는 cpu마다 다른데 Intel x86 cpu의 경우 cache line의 크기는 64byte이다. 만약에 double이 4-byte alignment된다고 가정하자. 그러면 double variable이 0x3C ~ 0x43에 위치하고, cache line 1이 0x0 ~ 0x3F , cache line 2가 0x40 ~ 0x7F 의 메모리 주소의 data를 가지고 있다고 생각해보자. 이 경우 double variable의 data를 읽으려면 cache line 1과 cache line 2