12장 메모리관리. [319] DATE : 2015-06
Download
Report
Transcript 12장 메모리관리. [319] DATE : 2015-06
12장
Memory Management
15.06.29
CSLAB
Park Se Won
Page
struct page{
unsigned long flags;
atomic_t _count;
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping;
pgoff_t index;
struct list_head lru;
void *virtual;
};
모든 물리적 페이지 관리용
페이지소유자
• Userspace process
• Dynamic data
• Static kernel code
• Page cache
2
Page
형 ( type )
struct page{
};
이름
unsigned long
flags
atomic_t
_count
unsigned int
_mapcount
unsigned long
private
spinlock_t
u.ptl
내용
페이지의 상태를 나타내는 플래그,
플레그 배열로 페이지 프레임이 속하는 지역 번호를 가진다.
페이지의 참조 카운트.
주소 공간에 매핑되고 있는 수.
페이지 프레임을 참조하는 페이지 테이블 엔트리의 수.
( 없으면 -1 )
용도에 따라 제각기 다름
페이지를 사용하는 커널 구성 요소가 이용.
( ex. 버퍼 페이지의 경우 버퍼 헤드의 주소 )
페이지가 사용하지 않는 것이라면 필드는 버디 시스템을 사용
페이지 테이블 엔트리 변경 시의 잠금용
struct address_space * mapping
파일 캐시로 사용되고 있을 때, 그 주소 영역의 구조체
pgoff_t
index
페이지 단위의 파일 오프셋, 또는 스왑 영역의 인덱스
( mapping이 스왑 캐시의 경우 )
다른 용도와 함께 일부 커널 구성 요소가 사용한다. 예를 들어, 페이지 디스크 이미지
나 익명 영역 내에서 페이지에 저장될 자료의 위치를 식별한다. 또는 스왑된 페이지
식별자를 저장.
struct list_head
lru
LRU 리스트용 ( zone 구조체 헤드 )
오랫동안 사용하지 않은 페이지의 이중 연결 리스트에 대한 포인터를 담는다.
void *
virtual
kmap되어 있을 때의 가상 주소
페이지의 가상 주소를 나타낸다. 보통 이 값은 단순히 가상 메모리 상의 페이지 주소.'
unsigned long flags;
atomic_t _count;
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping;
pgoff_t index;
struct list_head lru;
void *virtual;
3
Page
변수
내용
flag
페이지 상태 저장
Modify, Locking 등 각 비트별로 총 32가지 상태 저장 가능
<linux/page_flags.h>에 저장되어있음
_count
페이지 사용횟수
-1: 페이지 사용 안하는 중
Page_count() 함수 이용; 0: 페이지 사용 안하는 중
virtual
가상 메모리 상의 페이지 주소
NULL: 고정된 주소가 아닐 때, 동적으로 설정됨
struct page{
unsigned long flags;
atomic_t _count;
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping;
pgoff_t index;
struct list_head lru;
void *virtual;
};
4
Page
플래그명
의미
PG_locked
페이지에 락이 되어 있다. 예를 들어 디스크 입출력 연산과 관련된 페이지이다.
PG_error
페이지 전송 중 입출력 에러가 발생한다.
PG_referenced
이 페이지를 최근에 접근하였다.
PG_uptodate
디스크 입출력 에러가 발생하지 않고, 읽기 작업을 마친 후에 플래그를 설정한다.
PG_dirty
페이지를 수정하였다.
PG_lru
페이지가 활성 또는 비활성 페이지 리스트에 들어 있다.
PG_active
active 리스트에 연결되어 있다.
PG_slab
페이지를 슬랩으로 사용한다.
PG_highmem
페이지 프래임이 슬랩에 들어 있다.
PG_checked
EX2와 EX3 파일 시스템에서 사용하는 플래그이다.
PG_arcjh_1
아키텍쳐 종속, i386에서는 미사용.
PG_reserved
커널 코드용으로 예약했거나 사용할 수 없는 페이지 프레임이다.
PG_writeback
writepage 메소드에 의해 디스크에 쓰는 중이다.
PG_nosave
시스템 일시 중지/재개를 위해 사용.
PG_compound
페이지 프레임이 확장 페이징 매커니즘을 통해 처리된다.
PG_swapcache
페이지가 스왑 캐시에 속한다.
PG_mappedtodisk
페이지 내 모든 자료는 디스크에 할당된 블록에 해당한다.
PG_reclaim
메모리 해지를 위해 페이지가 디스크에 쓰여 졌다고 표시한다
PG_nosave_free
시스템 일시 중지/재개를 위해 사용된다.
PG_private
추가로 필요한 자료를 저장한다.
5
Zone
WHY
-특정 메모리 주소로만 DMA 수행 가능
• x86인 경우 ISA 장치는 메모리 앞부분 16MB만 접근 가능
• PCI장치는 24bit 주소 공간에만 DMA 수행 가능
-일부 아키텍쳐에서는 가상적으로 접근할 수 있는 것보다 더 많은 양의 메모리를
물리적으로 접근할 수 있다. 따라서 일부 메모리는 커널 주소 공간에 상주할 수
없다.
allocated as… Physical > Logical, 논리적주소로 물리적 주소를 매핑할 수 없다.
<linux/mmzone.h>에 정의
•
•
•
DMA
NORMAL
HIGHMEM
lock:구조체 스핀락 데이터 보호 O, 페이지 보호X
watermark: 해당 구역 메모리 사용량
name: DMA, NORMAL, HighMem
<mm/page_alloc.c>
6
Zone
구역
내용
물리적 메모리
ZONE_DMA
DMA 가능 페이지
< 16MB
ZONE_DMA32
32비트 장치들만 접근 가능
ZONE_NORMAL
일반적으로 접근 가능한 페이지
16-896MB
ZONE_HIGHMEM
커널 주소 공간에 상주하지 않는 페이지;
동적으로 연결되는 페이지, 상위 메모리
<896MB
<linux/mmzone.h> 에 정의
ZONE_MOVABLE
ZONE_PADDING
Logical
http://gemsres.com/story/sep07/431838/smarduch_fig1.jpg
7
Zone
Normal page
DMA 구역 확보를 위해
ZONE_NORMAL 사용
http://gemsres.com/story/sep07/431838/smarduch_fig1.jpg
8
Interface 페이지 할당
<linux/gfp.h>
struct page * alloc_pages(gfp_t gfp_mask, unsigned int order)
1<<order 만큼 연속된 물리적 페이지를 할당
첫번째 페이지의 page 구조체 포인터 반환
오류: NULL 반환
void * page_address(struct page *page)
물리적 페이지의 논리적 주소 포인터 반환
Unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
alloc_pages의 동작
첫 번째 페이지의 논리적 주소 반환
Unsigned long get_zeroed_page(unsigned int gfp_mask)
__get_free_page()함수와 동일
할당된 페이지 내용을 0으로 채움 의도하지 않은 데이터가 있을 수 있음
struct page * alloc_page(gfp_t gfp_mask)
Unsigned long __get_free_page(gfp_t gfp_mask)
order = 0
1페이지
9
Interface 페이지 반환
void __free_pages(struct page *page, unsigned int order)
void free_pages(unsigned long addr, unsigned int order)
void free_page(unsigned int addr)
할당받은 페이지만 반환
잘못사용하면 메모리 파괴됨
Ex)
unsigned long page = __get_free_paes(GFP_KERNEL, 3);
if(!page){
/*메모리 부족*/
return –ENOMEM;
}
free_pages(page, 3);
10
kmalloc()
<linux/slab.h>
void * kmalloc(size_t size, gfp_t flags)
최소 size 바이트 길이를 가진 메모리 영역의 포인터 반환;물/논리적으로 연속
오류: NULL 반환
void kfree(const void *ptr)
kmalloc() 을 통한 메모리 해제
Ex)
char *buf
buf = kmalloc(BUF_SIZE, GFP_KERNEL);
if(!buf)
/*오류 처리*/
kfree(buf);
11
vmalloc()
<linux/vmalloc.h>선언, mm/ vmalloc.c 구현
void * vmalloc(unsigned long size)
최소 size 바이트 길이를 가진 메모리 영역의 포인터 반환;논리적으로 연속
오류: NULL 반환
*페이지 테이블의 정보를 수정해서 논리적 주소를 연속적으로 만듦
*페이지 단위로 페이지 테이블에 등록 TLB를 더 사용
kmalloc에 비해 *성능 저하
void vfree(const void *addr)
vmalloc() 을 통한 메모리 해제
Ex)
char *buf
buf = vmalloc(16 * PAGE_SIZE); /*get 16 pages*/
if(!buf)
/*오류 처리*/
vfree(buf);
12
Free list
Normal
Free list
free
free
Add
deallocation
free list
Using object cache
13
Free list
Normal
Free list
new
new
p = malloc()
free list
initialization
14
Free list problem
Memory
lack
Slab layer
Kernel
Can not control
Which one?
free list
15
Slab layer
자주 사용하는 자료구조는 캐시
*단편화 유발 방지 free list is sequential
객체, 페이지, 전체 캐시 등의 정보를 알고 있으면 정교한 처리 가능
일부 캐시가 프로세서 단위로 되어 있다면 SMP 락 없이 할당, 해제 가능
NUMA를 지원 하는 경우 메모리를 요청한 노드에 있는 메모리 할당 가능
여러 객체가 같은 캐시에 섞이지 않게, 저장되는 객체에 표시 할 수 있어야 함
*가용 메모리에서 충분한 연속된 메모리 공간을 찾을 수 없는 상황
SMP
waiting
작업을 위한 데이터가 메모리의 어느 위치에 있는지 상관없이 작업할
수 있도록 프로세서에게 허용.
16
Slab layer
Object
Slab
Object
Object
Cache
Object
Slab
Object
17
Slab layer
객체 요청
부분사용
mm/slab.c
kmem_list3
slabs_full
slabs_patritial
slabs_empty
미사용
모두사용: 해제된 객체가 없음
kmem_getpages()
부분사용: 할당, 해제된 객체
미사용: 할당된 객체가 없음
새로운 Slab
18
Slab layer
Struct slab{
struct list_headlist;
unsigned long colouroff;
void *s_mem;
unsigned int inuse;
kmem_bufctl_t free;
};
static inline void * kmem_getpages(struct kmem_cache *cachep, gfp_t flags){
void *addr;
flags |= cachep->gfpflags;
adr = (void*) __get_free_pages(flags, cachep->gfporder);
}
return addr;
19
Slab layer
Struct kmem_cache * kmem_cache_create(const char *name,
size_t size,
휴면 상태로 전환 될 수 있기 때문에
size_t align,
인터럽트 컨텍스트에서는 호출하면안됨
해제: int kmem_cache_destroy(struct kmem_cache *cachep)
unsigned long flags,
모든 슬랩이 비어 있어야 함
호출하는 동안 캐시에 접근하면 안됨
void (*ctor) (void*));
name: 캐시 이름
size: 캐시에 들어갈 항목의 크기
align,: 슬랩 내부의 첫 번째 객체의 오프셋 default 0
flags: 캐시 동작 제어 default 0
ctor: 캐시 생성자
FLAGS
내용
SLAB_HWCACHE_ALIGN
캐시 라인에 맞춰 정렬, 잘못된 공유 현상 방지, 메모리 사용량 증가, 성능우선
SLAB_POISON
a5a5a5a5 로 슬랩을 채움 (poisoning) 초기화 하지 않은 메모리 탐지
SLAB_RED_ZONE
버퍼 경계 넘침 현상 감지, 할당된 메모리 양측에 red zone 을 끼워 넣음
SLAB_PANIC
오류 시 panic 발생, VMA 할당 처럼 할당 작업이 절대로 실패해서는 안 될 때 사용
SLAB_CACHE_DMA
DMA 처리 가능한 메모리에 슬랩을 할당, ZONE_DMA에 있어야 하는 경우 필요
20
Slab layer
void * kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
캐시에 들어있는 객체의 포인터 반환
내부 슬랩에 해제된 객체가 없으면 kmem_getpages() 호출
flags 인자가 __get_free_pages() 함수로 전달
void kmem_cache_free(struct kmem_cache *cachep, void *objp)
객체 해제 후 슬랩에 반환
cachep에 있는 objp 에 해제 표시
21
Stack – 단일 페이지 커널 스택
프로세스별 메모리 사용량 최소
단편화: 메모리 할당 작업이 어려워짐
인터럽트 핸들러: 프로세스의 커널 스택 사용
커널 스택 사용량 증가
Interrupt Stack
한 페이지
인터럽트 핸들러가 사용하는 각 프로세서 별로 존재
중단된 프로세스의 커널 스택 공유 안함자체스택
22
상위 메모리 연결
상위 메모리에 있는 페이지는 고정된 커널 주소 공간 값이 없을 수 있다; 논리적 주소가 없을 수 있다
고정연결
<linux/highmem.h>
void *kmap(struct page *page)
휴면상태로 전환 될 수 있음
페이지 위치가
하위메모리: 페이지의 가상 주소 반환
상위메모리: 고정 연결 주소 반환
void kunmap(struct page *page)
고정연결 개수 제한 연결 해제
임시연결
temporary, atomic mapping
컨텍스트가 휴면이 불가능한 상황일 때
void *kmap_atomic(struct page *page,
enum km_type type)
type: 연결의 목적
<asm-generic/kmap_types.h>에 정의
메모리 연결은 프로세서별로 고유
커널 선점 비활성
void kunmap_atomic(void *kvaddr,
enum km_type type)
연결 해제, 잊어버리기만 함(덮어 씌워짐)
23
CPU별 할당
int cpu;
cpu = get_cpu();
my_percpu[cpu]++;
printk(“my_percpu on cpu=%d is %lu\n”, cpu, my_percpu[cpu]);
put_cpu();
Index
data
0
1
2
SMP
unsigned long
my_percpu[NR_CPUS];
…
24
CPU별 할당
WHY
-Lock이 필요 없을 수 있음
-Lock보다 비용이 적은 커널 선점 비활성화를 사용
-Cache invalidation 를 줄여줌
캐시 동기화 상태 유지 cache invalidation thrashing the cache 성능저하
A프로세서가 B프로세서 캐시조작 A프로세서는 캐시를 비우거나 갱신
25
New percpu interface
2.6 Kernel 이전 커널에서는 호환이 안됨
컴파일 시점의 CPU별 데이터
실행 시점의 CPU별 데이터
DEFINE_PER_CPU(type, name);
프로세스 별로 type name변수 생성
DECLARE_PER_CPU(type, name);
위 변수를 다른 곳에서 사용 하는 경우
<linux/percpu.h>
void *alloc_percpu(type); //매크로
void *__alloc_percpu(size_t size, size_t align);
void free_percpu(const void*);
get_cpu_var(name)++;
현재 프로세서의 name값 증가
put_cpu_var(name)++;
커널 선점 활성화
get_cpu_var(ptr);
현재 프로세서의 해당 데이터를 가리키는
void 포인터 반환
put_cpu_var(ptr);
작업 마치고 커널 선점 활성화
per_cpu(name, cpu)++;
지정한 프로세서의 name값 증가
선점 비활성화, Locking 없음
현재 프로세서 조작만 원자적 실행 보장
void *percpu_ptr;
unsigned long *foo;
percpu_ptr = alloc_percpu(unsigned long);
if(!ptr) //오류 처리
foo = get_cpu_var(percpu_ptr);
put_cpu_var(percpu_ptr);
26
Summrary
메모리 할당: 일반적으로 kmalloc() 함수 이용
(1)GFP_ATOMIC, (2)GFP_KERNEL 플래그 이용
Case (1): 휴면상태 전환X, 우선순위가 높은 할당 작업 진행
Case (2): 휴면 상태 전환O
like process context code without spinlock
상위메모리할당: alloc_pages() 함수 이용
가상적으로 연결필요: vmalloc() 함수 이용, 성능은 kmalloc()보다 낮음
큰 자료구조 생성 및 해제: 슬랩 캐시 사용 고려, freelist 제공
27