IA-32에서, 메모리 캐쉬는 물리 주소를 키로 하고 있기 때문에 아무것도

Download Report

Transcript IA-32에서, 메모리 캐쉬는 물리 주소를 키로 하고 있기 때문에 아무것도

메모리 관리
주소변환
가상 주소 공간
0번지부터 시작되는 단일 선형 주소 공간
과거 유닉스에서 도입하고 있었던 모델과 같은 모델
가상 주소 공간의 크기는 CPU 아키텍쳐에 따라 달라짐.
32비트 아키텍쳐에서는 4GB(Because 2^32)
물리적으로 메모리에 바로 대응하는 것이 아니라, 가상 주소
공간이 필요한 이유는 물리 메모리가 제한적이기 때문이다.
페이지(page)
메모리를 일정한 공간으로 나눈 것
페이지 또는 프레임이라고 함.
가상 페이지 - 가상 주소 공간을 나눈 것
물리 페이지 - 물리 메모리 공간을 나눈 것
페이지의 크기는 CPU 아키텍쳐에 따라 다름
일반적으로 IA-32에서 4KB
1GB 기준으로 = 262,144 개의 독립된 페이지 존재
4GB 기준으로 = 1,048,576 개의 독립된 페이지 존재
struct page {
page_flags_t flags;
플래그
페이지는 4KB이기 때문에 페이지 선두 주소의 하위 12비트는
0이 된다. 그래서 각 테이블의 하위 12비트를 다양한 플래그로
사용하고 있다.
4 byte = 32 bits
20 + 12 bits
2^12 = 4096
1 KB = 1024 byte
4096 byte
페이지 변환 테이블
가상 주소 공간(페이지)을 물리 주소 공간(페이지)에 대응하기
위한 테이블
이 테이블로 가상 주소 공간을 실제 물리 메모리 공간으로
대응시킨다.
페이지 변환 테이블은 가상공간마다 한개씩 존재하며,
따라서 프로세스 마다 존재한다.
컨텍스트 스위칭 할때마다 커널에서 바꾸는 자원이다.
가상 주소에서 물리 주소로의 변환은 하드웨어가 페이지 변환
테이블에 따라 자동적으로 수행하는데, 페이지 변환 테이블의
설정은 커널의 역할이다.
여기서 말하는 하드웨어는.. MMU(Memoery Management Unit)
가 아닐까 싶다..
typedef struct page *pgtable_t; // 페이지 테이블의 크기
리눅스의 페이지 변환 테이블
아키텍처에 관계없이 주소 변환을 구현, 메모리 관리하는
인터페이스의 필요성에 의해서 만들어지는 4단계 모델 구조
테이블 엔트리/관련 함수, 매크로
pgd_t, pud_t, pmd_t, pte_t
pgd_alloc
pgd_free
pgd_offset
pgd_none
pgd_bad
pgd_clear
페이지 테이블 엔트리 및 함수/매크로
페이지에 대한 접근 권한 : 읽기, 쓰기, 실행
페이지가 접근된 것을 나타내는 정보
페이지가 수정된 것을 나타내는 정보
pte_dirty - 페이지가 수정되었는지
pte_young - 페이지가 접근되었는지
pte_mkclean - 페이지가 수정되었다고 하는 정보를 정리
pte_mkold - 페이지가 접근되었다고 하는 정보를 정리
IA-32의 주소 변환 처리
세그먼트(segment)라고 하는 주소 변환처리가 존재
프로세스의 주소 공간을 논리 주소로 표현. 논리주소를 선형
주소로 바꾼 뒤, 페이징 처리에 의해 물리 주소로 변환
리눅스에서는 선형 주소 공간과, 가상 주소 공간을 동일한
것으로 처리하여, 선형 주소 공간 전체와 동일한 세그먼트를
정이하면 됨.
KERNEL_CS - 읽기, 실행 가능
KERNEL_DS - 읽기, 쓰기 가능
USER_CS - 읽기, 실행 가능
USER_DS - 읽기, 쓰기 가능
커널 모드와 사용자 모드가 변환될 때, 커널용 세그먼트와
사용자 세그먼트가 변환됨
IA-32의 페이지 변환 테이블
CR3 레지스터
IA-32의 페이지 변환 테이블(1)
bits : 10, 10, 12
경우의 수 : 1024, 1024, 4096
각 테이블의 크기는 4KB로 정확히 1페이지를 차지
IA-32의 페이지 변환 테이블(2)
PAE(Physical Address Extend)
TLB(Transfer Lookaside Buffer)
하드웨어는 가상 페이지와 페이지 프레임의 대응을 TLB라고
불리는 캐쉬로 관리. Why?
가상 주소를 접근할 때마다 페이지 테이블에 접근하게 되는데,
이는 직접 물리 주소에 접근하는 것과 비교해 보면 성능상의
차이가 크기 때문에 하드웨어는 예외 없이 캐쉬를 가짐.
TLB의 엔트리 추가는 하드웨어가 하고, 삭제는 커널이 한다.
찾아보니 엔트리 삭제 함수들뿐이다....
하드웨어는 어떤식으로 추가를하는것인가?
flush_tlb_all
flush_tlb_mm
flush_tlb_range
flush_tlb_page
메모리 캐쉬
아키텍처에 따라서 페이지 테이블을 변경했을 경우 메모리
캐쉬를 무효화할 필요가 있다고 함.
따라서 메모리 캐쉬를 무효화 하는 인터페이스 존재
IA-32에서, 메모리 캐쉬는 물리 주소를 키로 하고 있기 때문에
아무것도 할 필요가 없음.
커널 공간의 레이아웃
커널 공간의 레이아웃
커널 자신도 가상 주소 공간상에서 동작
아키텍쳐마다 자유롭게 설정할 수 있기 때문에 하나의
OS이더라도 아키텍쳐마다 구현 방법이 다르다.
리눅스의 메모리 관리는 원래 IA-32의 커널 공간 레이아웃을
바탕으로 설계 되어 있어서, IA-32 구현방법을 사용
세 개의 영역
*2가지의 하드웨어적 한계
어떤 하드웨어 장치는 특정 메모리 주소에 대해서만 DMA(Direct memory
access)를 수행 가능
어떤 아키텍처는 가상 주소보다 더 많은 물리적 주소를 사용할 수 있다. 그 결과
어떤 메모리는 커널 주소 공간에 영구 매핑되지 않게 된다.
*Solve*
이런 제한 때문에 리눅스에서는 세 개의 영역을 둔다.
ZONE_DMA : 이 영역은 DMA가 가능한 페이지를 포함한다.
ZONE_NORMAL : 이 영역은 일반적이고 정규적으로 매핑되는
페이지를 포함한다.
ZONE_HIGHMEM : 이 영역은 "상위 메모리"를 포함한다. 상위
메모리는 커널 주소 공간으로 영구적으로 매핑되지 않는다.
커널 공간 레이아웃
PAGE_OFFSET : 0xc0000000 = 3221225472...3GB
직접 엑세스 한계 : 0xf8000000 = 4160749568...3GB + 896MB
HIGHMEM 접근 영역 : 0xff800000 = 4286578688...
고정맵 영역 : 0xfffff000 - 0xffffe000 = 4096byte
직접 엑세스 한계 ~ HIGHMEM 접근 영역 = 약 120MB
0xfffff000 = 4GB - 4096Byte
0xffffffff = 4294967295
0xffffffff - HIGHMEM(0xff800000) = 8388607Byte... 약 7.9MB
프로세스 공간
프로세스 - 3GB
커널 공간 - 1GB
프로세스 공간과 커널 공간은 동일한 주소 공간에 존재
프로세스를 변환할 때, 페이지 글로벌 디렉토리를 변환하여
TLB도 정리(flush)(단, 이 경우 커널의 주소 범위는 TLB의
항목이 정리되지 않도록 설정되어 있다.)
직접 엑세스 영역(NORMAL)
커널은 모든 물리 메모리에 접근할 필요가 있다.
가상 주소 = 물리 주소 + PAGE_OFFSET
(즉, 물리 주소 = 가상주소 - PAGE_OFFSET)
다만 커널 공간이 1GB밖에 안 되는 관계로, 직접 매핑할 수
있는 영역은 896MB까지이다. 나머지 128MB는 커널 전용이다.
i386 구조의 한계 때문에 커널이 직접 접근할 수 있는 영역은 0 ~
896M까지이고, 897 ~ 1024M, 즉 128M 영역은 1G 이상의
영역과 데이터를 교환하는 방식으로 접근한다.
직접 엑세스 영역의 끝은 high_memory로 표시
고정 맵 영역
어느 고정의 가상의 주소로 임의의 물리 주소를 접근할 수
있으면 편리한 경우가 있음
0xffffe000 ~ 0xffff0000-1 : 1page분(4096byte)
( 책에서는 vsyscall용이라고 쓰여져 있음)
가상 페이지에 대응하는 페이지 테이블이 할당이 되어 있다.!
각각의 처리에 대해서 전용의 페이지 테이블 항목이 할당되어
있어서 인터럽트 처리의 연장으로도 안전하게 쓰인다.
HIGHMEM 영역
물리 메모리가 896MB를 넘을 경우, 스트레이트로 매핑을 할
수 없었던 물리 메모리에 접근하기 위한 영역이 상위
메모리(ZONE_HIGHMEM) 엑세스 영역이다.
kmap - page (1) 직접 엑세스 영역 : 지정한 페이지의 가상
주소를 그대로 반환.
(2) 상위 메모리(ZONE_HIGHMEM) : 상위 메모리
접근 영역이 비어 있는 페이지 테이블 항목에 매핑해서, 그 자상
주소를 반환. 비어 있는 영역이 없을 경우에는 빈 영역이 생길
때까지 대기
[ZONE_HIGHMEM] 접근용 인터페이스
void *kmap(struct page *page);
void kunmap(struct page *page); // TLB를 지연 매커니즘.
HIGHMEM 영역(2)
커널의 처리에 따라서는 확실히 상위
메모리(ZONE_HIGHMEM)에 접근할 필요가 있는 경우가 있다.
그래서 고정 맵 영역의 일부에 상위 메모리(ZONE_HIGHMEM)
접근용의 영역이 있다.
* 고정맵중 상위 메모리 접근용 인터페이스
void *kmap_atomic(struct page *page, enum km_type type);
void kunmap_atomic(void *kvaddr, enum km_type type);
kmap_atomic 함수 : 지정된 페이지를 지정된 인덱스에 맵핑
kunmap_atomic 함수 : kmap_atomic 함수와 1:1로 호출해야
한다. 커널 2.6에서 신경쓰지 않으면 선점 카운트의 일관성이
없어지게 되므로 주의가 필요하다.
커널 가상 영역
커널이 자신의 작업에 사용하는 영역
VMALLOC_START, VMALLOC_END 매크로로 시작주소와
끝주소(+1)을 표시
물리 메모리가 896MB인 경우 약 120MB가 된다.
vmalloc, vmalloc32, vfree, vmap, vunmap, ioremap, iounmap
vmalloc - 물리주소(비연속) but 가상주소(연속)
vmap - 지정한 크기의 가상 공간 할당, 그곳에 물리 페이지를
매핑.
ioremap - 지정한 크기의 가장 공간을 할당, 지정한 물리 주소를
매핑
커널 가상 영역 관리
vm_struct 구조체
연결리스트로 관리
vmlist로부터 addr이 작은 순서로 링크 되어 있음
vmalloc/vmap/ioremap 함수로 영역 획득시, vmlist의 선두부터
vm_struct 구조체를 뒤져서, 비어 있는 영역을 찾아가는 단순한
관리를 하고 있다. 또한 size는 지정된 크기보다 1페이지 정도
커진다. 마지막 1페이지는 물리 페이지를 할당하지 않고, 매핑도
되지 않는다. -> 프로그램의 오류로, 지정된 크기 이상의 영역에
접근하려고 할때 예외가 생길 수 있도록 하기 위한 것.
vfree/vunmap 으로 TLB 전체가 정리되는 구현으로 되어 있기
때문에, 빈번하게 할당하거나 해제를 수행하는 일은 성능상
좋지 않다고 생각된다.
그 밖의 커널 레이아웃
1.프로세스 공간과 커널 공간을 별도로?
2. 64bit 아키텍처...
64bit 아키텍처에서는 가상 주소 공간이 광대하기 때문에, 물리
메모리를 모두 직접 엑세스 할 수 있다.
Page 크기와 관련하여
페이지 크기가 Intel Architecture에서 4Kbyte인 이유?
-> 페이지 크기는 메모리 블록 하나가 디스크로부터 얼마만큼의
데이터를 읽어들여서 저장할 것인지를 결정하는 요소이다.
이 크기에 따라 디스크의 접근 횟수가 결정되어지므로 페이징
기법의 효율성을 결정하는 데 매우 큰 요소
아키텍쳐에 따라 크기가 다르다.
Motorola 68030 :256~32KBytes
IBM 360/67 1024Kbyes의 크기 사용
Page 테이블의 크기와 관련하여
만약 20bit(2^10 * 2^10)으로 참조 테이블의 프레임 개수를 결정한다면?
Intel Architecture
• 세그멘테이션 + 페이징
세그멘테이션
• 프로그램과 관련된 데이터들에 대하여 여러
개의 세그먼트들로 나누어 다루게 되며 이
세그먼트의 크기는 똑같을 필요가 없다.
세그멘테이션
• 16bit 시절…
CR3 레지스터
CR3 레지스터(2)
세그먼트 + 페이징
인텔 마이크로프로세서에서는 6개의 세그먼트용 레지스터를 가지고 있어서 한
프로세스에서 한순간에 6개의 세그먼트를 가리킬 수 있게 하였고 이 마이크로프로세서에서
메모리를 참조할 때에는 암시적이든 명시적이든 이 세그먼트 레지스터와 함께 사용되게
하였으며, 이렇게 지시되어진 세그먼트 레지스터는 세그먼트 디스크립터 테이블(Segment
Descriptor Table)을 참조하여 그 세그먼트에 대한 시작 주소를 가져오고 이 시작 주소와
엑세스하고자 하는 메모리 주소가 합해져 실제 선형 주소(Linear Address)를 만들어주게
된다. 그리고 이때 주소가 한계치를 넘는지 또는 해당 세그먼트가 엑세스하고자 하는
세그먼트에 대한 접근권한이 있는지 등을 체크하게 된다. 만약 이와 같은 접근에 문제가
있다면 운영체제에게 트랩을 발생시킴으로써 엑세스를 제한하도록 하고 있다.
또한 위에서 정상적인 접으로 확인된 경우 위에서 만들어진 선형 주소를 다시 페이지
변환에 의하여 CR3라는 특별한 레지스터를 참조하여 페이지 디렉토리(Page Directory)의
시작 위치를 알아내고 선형 주소의 상위 10비트를 페이지 디렉토리의 인덱스로 사용하여
페이지 테이블의 위치를 알아낸 후 선형 주소의 다음 페이지 인덱스를 사용하여 실제적인
물리적 메모리의 시작 어드레스를 알아내게 되며 이후의 오프셋(Offset) 데이터를 사용하여
실제의 물리적 어드레스를 알아내게 된다.
실제적인 메모리 할당
4KB보다 큰 경우 : 버디 할당자(Buddy Allocater)
- 이용 가능한 물리 메모리(빈 페이지)
- 빈 페이지를 관리하는 것
4KB보다 작은 경우 : 슬랩 할당자(Slab Allocater)
- 동적 할당(malloc), File구조체 등을 사용할 때
Buddy System
• Struct free_area free_area[MAX_ORDER];
– IA-32의 경우, MAX_ORDER == 11
• Free_area 구조체
– struct list_head free_list // 빈 페이지 연결리스트
– unsigned long nr_free // 이 오더의 빈 페이지 수
2.6.10 이전의 버디 관리
Page 할당
• Ex) 4페이지 연속으로 할당 하고 싶다?
– free_area[2]의 free_list를 본다.
Page 해제
• Free_list에 추가하거나 재귀적으로 상위
오더로 합침
But. 1Page 할당은?
• 1페이지 단위(오더 0)의 할당과 해제는
버디시스템을 이용하지 않는다.
• CPU의 캐쉬를 직접적으로 이용한다.
– hot, cold라고 부른다.
확보되어 있는 페이지 수가 low 이하가 되면 버디
시스템으로부터 batch 페이지분을 가져온다. 확보한
페이지가 high 이상이 되면 버디 시스템에 batch 페이지분을
반환한다.
per_cpu_pages
Slab Allocator
• 정적으로 확보하기 힘든 메모리의 동적
확보를 위한 것
• 캐쉬 헤더
– 슬랩 내의 오브젝트가 전부 사용 중인 슬랩
리스트
– 슬랩 내의 오브젝트가 사용중과 미사용의 것이
혼재된 슬랩 리스트
– 슬랩 내의 오브젝트가 전부 미사용인 슬랩 리스트
• slab 구조체의 free멤버가 리스트 선두의 빈
오브젝트를 가리킴.
struct kmem_list3
제어용 헤더
• 제어용 헤더
슬랩의 구조
오브젝트 할당
오브젝트 해제
슬랩 할당자내에서 오브젝트 처리
Pentium Processor에서의 캐시 구조
캐쉬 쓰기 정책
• Write Through
– CPU에서 메모리에 쓰기 요청을 할 때마다 캐쉬의
내용과 메인 메모리의 내용을 같이 바꾸는 방식
• Write Back
– CPU에서 메모리에 대한 쓰기 작업 요청 시
캐시에서만 쓰기 작업과 그 변경 사실을 확인할
수 있는 표시를 하여 놓은 후 캐시로부터 해당
블록의 내용이 제거될 때 그 블록을 메인
메모리에 복사함으로써 메인 메모리와 캐시의
내용을 동일하게 유지하는 방식
Lazy write
• [Windows]
• 캐시 관리자의 지연 쓰기 기능(Lazy write)이 시스템 작업 스레드에서
초당 1회 실행되고 시스템 캐시 내 변경 페이지의 1/8을 디스크에 쓰도록
한다. 만일 갱신 페이지의 생성율이 지연 쓰기가 결정하는 써야 할 양보다
큰 경우, 지연 쓰기는 갱신 페이지의 생성률에 맞추어 필요한 만큼의 변경
페이지를 추가로 디스크에 쓴다. 실제 I/O 작업을 실행하는 것은 시스템
전반의 임계 작업 스레드 풀(pool)의 시스템 작업 스레드들이다.
-Windows Internals-
[Lazy Writer Thread]
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
http://msdn.microsoft.com/en-us/library/ms885487.aspx
The lazy-writer thread uses the following algorithm.
if (event set indicating that there are dirty sectors to commit) {
while (TRUE){
Enter main critical section protecting the cache from main threads;
if (no more dirty sectors) {
Leave main critical section;
break;
}
Find first dirty run of sectors to commit;
Commit those dirty sectors;
Leave main critical section;
}
}
Reset event indicating there are no dirty sectors to commit.
CR0
• CD(Cache Disable)
– 1로 세트 될시, 모든 캐시 동작이 멈춤.(시스템
전체의 메모리 접근에 대하여)
• NW(Non-Cache Write Through)
– 1로 세트 될시, 캐쉬의 쓰기 정책이 WriteBack형태로 동작. 0이면 Write Through 방식
CR3
• PCD(Page Cache Disable)
– CD비트와 유사, 단지 해당페이지에 대해서만
영향.
• PWT(Page Write Through)
– 해당 페이지에 외부 캐시의 쓰기 정책을 결정.
내부 캐시의 쓰기 정책에는 영향을 안 미침.
TLB(Translation Lookaside Buffer)
TLB- 보충
• Instruction TLB, Data TLB
• CR3 레지스터 변경시 TLB 내용
무효화(Global 비트가 셋팅되어있는 페이지는
제외)…=Process Switching시에 무효화 되는
것이지 않을까?
요구 페이지 처리
• (1) 마이크로프로세서는 프로그램이 접근하고자 하는 메모리가 유효한지
알아보기 위해 그 페이지 테이블의 유효비트를 살펴본다.
• (2) 1번의 검사 결과 해당 페이지의 유효 비트가 0으로 세트되어 유효하지
않다면 페이지 폴트(Page Fault)인터럽트를 발생시킨다.(CR2 레지스터에
페이지 폴트가 발생한 주소를 세트, Page Fault 인터럽트 = 14)
• (3) 인터럽트를 받은 운영체제는 메인 메모리에서 빈 공간을 찾아본다.
그리고 메인 메모리에 빈 공간이 없다면 페이지 교체 작업을 수행해 빈
공간을 확보한다.
• (4) 새로 할당된 빈 공간에 해당 페이지의 내용을 디스크로부터
읽어들인다.
• (5) 요청한 페이지가 메모리에 있다는 사실을 마이크로프로세서가 인식할
수 있도록 페이지 테이블의 내용을 갱신한다.
• (6) 트랩에 의해 발생한 인터럽트를 빠져나감으로써 페이지 에러가
발생한 명령어가 다시 시작되도록 한다.
Prepaging
• 대부분의 프로그램이 참조한 근처의
메모리를 다시 참조한다는 지역성(Locality)의
특성을 이용해 요구한 페이지 외에 그 근처의
페이지까지 함께 불러들이는 방식
• 읽어들이는 페이지가 코드 페이지/데이터
페이지 여부에 따라 읽어들이는 크기가
달라짐
Paged Memory, NonPaged Memory
• Page Out -> copy Page from memory to hard
disk
• Page In -> copy Page from hard disk to memory
• Paged Memory = Page In과 Page Out이 가능한
메모리
• NonPaged Memory = Page In과 Page Out이
가능하지 않은 메모리로 운영체제 코드와
디바이스 드라이버 내용이 여기 위치함
Page Replacement Policy
• 새로운 페이지를 디스크에서 읽어 메모리에
저장해야 할 때 기존의 메모리 페이지 중
어떠한 페이지를 디스크로부터 내려야
할지를 결정하는 것을 말한다.
• LRU(Least Recently Used)
Locality
Additional Reference Bits
Second Chance
FIFO
-Page Frame Number Database( Windows )
Memory
Management
Algorithm
Thrashing
• 만일 어떤 프로세스가 너무 적은 양의 메모리 페이지
할당으로 실제 프로세스가 원하는 명령어의 실행 시간보다
페이지 부재의 발생으로 페이지 교체를 수행하는 데 소비하는
시간이 더 많아지는 현상
• 프로세스의 개수가 늘어날수록 각각의 프로세스가 가질 수
있는 메모리 페이지 개수는 줄어들 것이고, 각 프로세스가
사용할 수 있는 메모리 페이지의 감소는 더 많은 페이지
교체가 발생하게 될 것이며, 이는 실제CPU가 어떠한 작업을
처리하는 데 보내는 시간보다 페이지 교체를 위한 디스크 I/O
작업을 기다리는 데 소비하는 시간이 더 많아지기 때문
Working Set
• 하나의 프로세스에서 자주 참조하는
페이지들의 집합
• 작업세트의 개념을 이용하는 시스템에서는
이러한 페이지들에 대하여 항상 메인
메모리에 유지시키는 것을 원칙으로 함
EFLAGS
약칭
종류
플래그의 정식 명칭
DF
Control
Direction flag
CF
Status
Carry flag
PF
Stauts
Parity flag
AF
Status
Auxiliary carry flag
IF
System
Interrupt flag
ZF
Status
Zero flag
IOPL
System
I/O privilege level
SF
Status
Sign flag
NT
System
Nested task
OF
Status
Overflow flag
RF
System
Resume flag
VM
System
Virtual 8086 mode
AC
System
Alignment check
VIF
System
Virtual interrupt flag
VIP
System
Virtual interrupt pending
ID
System
ID flag
TF
System
Trap flag
Status Flag
약칭
종류
플래그의 정식 명칭
의미
CF
Status
Carry flag
연산 결과의 자리 올림, 빌림
PF
Stauts
Parity flag
연산 결과의 패리티 비트
AF
Status
Auxiliary carry flag
연산 결과의 비트 3부터 자리 올림,
빌림
ZF
Status
Zero flag
비교 결과가 0일때 1
SF
Status
Sign flag
연산 결과가 음수일때 1
OF
Status
Overflow flag
연산 결과가 양수, 음수의 한계 초과
vmalloc
• 물리적으로 연속적인 공간이 아니라,
가상적으로만 연속인 메모리
– 버디시스템으로부터 1페이지 단위로 할당
•
•
•
•
•
vfree
vmap
vunmap
ioremap
iounmap
kmalloc
Memory Pool
• 긴급시에 할당할 수 있도록 만들어놓은
인터페이스
• mempool_t *mempool_create(int min_nr,
mempool_alloc_t *alloc_fn, mempool_free_t *free_fn,
void *pool_data);
• void *mempool_alloc(mempool_t *pool, gfp_t
gfp_mask);
• void mempool_free(void *element, mempool_t *pool)
• void mempool_destory(mempool_t *pool);
Memory 할당비교
• [Linux]
–
–
–
–
Buddy
Slab
Lazy Buddy
Slub
• [Windows]
– VirtualAlloc
– Slab
Windows Memory Allocation
•
•
•
•
•
•
•
•
•
•
•
•
[VirtualAlloc]
가상 주소 공간의 각 페이지는 미사용(free), 예약, 수용 3가지 상태를 지닌다.
예약/수용 이라는 두 종류의 할당방법을 제공
- VirtualAlloc -> 가상 메모리 할당
- VirtualFree -> 가상 메모리 할당 해제
- VirtualProtect -> 접근 권한 변경
- VirtualQuery -> 지정한 주소의 페이지 정보 얻기
[HeapAlloc]
'힙 할당' - 어느 정도 결정된 크기의 메모리 영역(힙)을 준비해 두고, 필요한 크기의 메모리를
그곳에서 잘라 사용하는 구조이다. C언어의 malloc 함수 등의 할당 방법과 같다.
Windows에서는 프로그램 시동 시에 프로그램 전용 힙을 가상 메모리에 하나
준비한다. 이를 디폴트 힙이라고 한다. 디폴트 힙은 일부 Win32 API에서 내부 메모리를
할당해서 사용하기도 하지만 프로그램 자신이 사용해도 된다.
Windows Memory Allocation
•
•
•
•
•
•
•
•
•
•
•
•
•
GetProcessHeap -> 디폴트 힙의 핸들을 얻는 API
HANDLE HeapCreate( // 반환값: 생성된 핸들
DWORD flOptions, // 옵션
SIZE_T dwInitialSize, // 초기 힙 크기(초기 수용 크기)
SIZE_T dwMaximumSize // 최대 힙 크기(초기 예약 크기)
);
LPVOID HeapAlloc( // 반환값: 할당된 블록의 시작 주소
HANDLE hHeap, // 할당된 힙 리턴
DWORD dwFlags, // 옵션
SIZE_T dwBytes // 할당된 크기
);
프로세스 공간 관리
ELF specification
•
•
•
•
•
•
•
•
•
•
•
•
ELF specification
fs/elf_binfmt.c
* exec() 에 지정된 경로 이름
* 전체 프로세스 환경(변수)
* 모든 argv 문자열
* argc
* 보조 벡터
C 응용 프로그램에서는 main()이 첫번째로 실행되는 함수가 아니다.
main()보다 먼저 실행되는 함수는 __libc_start_main(), _start(), __libc_csu_init()
등이 있다.
/proc/[pid]/maps
•
•
•
•
•
•
•
•
•
•
address
perms offset dev inode pathname
08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
08056000-08058000 rw-p 0000d000 03:0c 64593 /usr/sbin/gpm
08058000-0805b000 rwxp 00000000 00:00 0
40000000-40013000 r-xp 00000000 03:0c 4165 /lib/ld-2.2.4.so
40013000-40015000 rw-p 00012000 03:0c 4165 /lib/ld-2.2.4.so
4001f000-40135000 r-xp 00000000 03:0c 45494 /lib/libc-2.2.4.so
40135000-4013e000 rw-p 00115000 03:0c 45494 /lib/libc-2.2.4.so
4013e000-40142000 rw-p 00000000 00:00 0
bffff000-c0000000 rwxp 00000000 00:00 0
•
•
•
•
•
r = read
w = write
x = execute
s = shared
p = private (copy on write)
/proc/[pid]/maps
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
각각의 라인은 세그먼트를 나타낸다.
[1] 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
프로그램의 실행 명령이 있고, 수정코드가 빠져 있으므로 (r-xp) 코드 세그먼트일 가능성이 높다.
[2] 08056000-08058000 rw-p 0000d000 03:0c 64593 /usr/sbin/gpm
읽기와 쓰기는 가능하나, 실행은 불가능하다. 즉 데이터세그먼트일 가능성이 높다.
여기에 위치하는 데이터는 초기화된 전역변수라고 한다.
/lib/ld-2.2.4.so: 공유 라이브러리 링커이다.
공유 라이브러리를 동적으로 링크하는 모든 실행 파일은 당연히 공유 라이브러리 링커를 가장 먼저 메모리에 적재한다.
링커는 링크된 공유 라이브러리에서 모든 외부 심볼을 결정해야 하므로, 메모리에 가장 먼저 사상되어야 한다.
공유 라이브러리 확인 방법은 ldd
[3] bffff000-c0000000 rwxp 00000000 00:00 0
스택 변수가 저장되는 곳이다. 처음부터 깔끔하게 스택변수가 들어가는 것이 아니라, 스택 변수와 관련된 메타 데이터가
저장된다. ( 프로그램의 환경, 인수 개수, 인수 벡터 등과 같은 정보 - ELF 명세)
* 링커 정보 일부도 여기에 저장된다고 한다. *
*스택은 아래로 커지므로 c0000000 - ELF명세를 뺀 값에서 시작한다.
c0000000 을 초과하면은 알다시피 대망의 커널 세그먼트..
프로세스 가상공간을 기존의 3:1 분할이 아니라 4G를 사용하게 하는 방법이 있다고 한다.
아래의 패치는 1GB 커널 세그먼트를 각 프로세스의 주소 공간 밖으로 옮긴다. 따라서 응용프로그램은 전체 주소 공간
4GB를 사용 가능하다.
인터럽트와 트랩
인터럽트란?
• 주변 장치와 커널이 통신하는 방식 중의 하나
• 주변 장치나 CPU가 자신에게 발생하는
사건을 리눅스 커널에게 알리는 매커니즘
• 인터럽트 핸들러
• 외부 인터럽트 – 하드웨어적인 사건
• 트랩 – 소프트웨어적인 사건, 예외
처리(exception handling) ex) divide_by_zero,
세그멘테이션 폴트, 페이지 폴트, 보호 폴트,
시스템 호출 등
IDT(=IVT)
• Interrupt Descriptor Table(=Interrupt Vector
Table)
• 외부 인터럽트와 트랩을 처리하기 위한
함수의 주소 값을 가지고 있는 테이블이다.
• 0~31번까지는 트랩용으로 예약, 32번부터
외부 인터럽트가 사용가능
외부 인터럽트
fault
인터럽트
트랩
trap
abort
복귀
• ret_from_exception()
– 시스템 콜을 제외한 트랩
• ret_from_intr()
– 일반적인 외부 인터럽트
• ret_from_sys_call()
– 시스템 콜