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