Linux 메모리 관리 (Linux 커 널 깊이 이해)

31973 단어
리 눅 스 의 메모리 관 리 는 실제 적 으로 80x 86 의 하드웨어 세그먼트 와 페이지 회 로 를 통 해 논리 주 소 를 물리 적 주소 로 바 꾸 었 다.
물리 적 메모리 중 일 부 는 커 널 에 계속 (Permanently) 매 핑 되 어 사 용 됩 니 다. 이 부분 은 커 널 의 코드 와 커 널 의 정적 데이터 구조 체 를 저장 하 는 데 사 용 됩 니 다.이러한 물리 적 메모 리 를 커 널 에 계속 비 추 려 는 이 유 는 이러한 내용 (코드, 정적 데이터 구조) 이 전체 운영 체제 가 실행 되 는 과정 에서 끊임없이 인용 되 어야 하기 때 문 입 니 다. 물리 적 메모리 에 있 는 위 치 를 동적 으로 분배 하고 번역 하 는 방식 으로 유지 하려 면 CPU 시간 이 너무 많이 걸 립 니 다.
이런 방식 은 공간 으로 시간 을 바 꾸 는 전략 으로 이해 할 수 있다.
 
물리 메모리 의 나머지 부분 은 동적 메모리 입 니 다.
동적 메모 리 는 사용자 상태의 각 프로 세 스 에 필요 할 뿐만 아니 라 커 널 자체 도 필요 합 니 다.
 
Page Frame Management
Memory Area Management
물리 적 으로 연 결 된 메모리 영역 을 관리 하 는 두 가지 방식 입 니 다.
 
Noncontiguous Memory Area Management
물리 적 으로 연결 되 지 않 는 물리 적 메모리 영역 을 처리 하 는 방식 입 니 다.
 
Page Descriptor
커 널 은 모든 페이지 의 현재 상 태 를 유지 해 야 합 니 다.
예 를 들 어 어떤 물리 페이지 가 현재 누가 사용 하고 있 는 지 구분 할 수 있어 야 한다.
1. 사용자 상태의 프로 세 스
2. 커 널 코드
3. 내부 핵 상태의 데이터 구조
 
마찬가지 로 Dynamic Memory 에서 분 배 된 물리 적 메모리 페이지 가 현재 어떤 상태 에 있 는 지 구분 할 수 있어 야 합 니 다.
1. 석방 상태
2. 사용자 상태의 프로 세 스 데 이 터 를 저장 합 니 다.
3. 소프트웨어 하 나 를 저장 하 는 Cache
4. 동적 분 배 를 저장 하 는 커 널 의 데이터 구조
5. 장치 가 구동 하 는 캐 시 데 이 터 를 저장 합 니 다.
6. 커 널 모듈 을 저장 하 는 코드
 
각 페이지 의 설명 구조 체 는 하나의 struct page 의 인 스 턴 스 로 저 장 됩 니 다. 이 인 스 턴 스 는 mem 에 저 장 됩 니 다.맵 배열 중.
각 struct page 크기 는 32 바이트 이기 때문에 약 1% (32 / 4096) 의 물리 적 메모 리 를 사용 하여 이 배열 을 저장 합 니 다.
 
커 널 은 페이지 구조 체 의 위 치 를 얻 기 위해 다음 과 같은 매크로 를 제공 합 니 다.
   1: #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
   2:  
   3: /*
   4:  * supports 3 memory models.
   5:  */
   6: #if defined(CONFIG_FLATMEM)
   7:  
   8: #define __pfn_to_page(pfn)    (mem_map + ((pfn) - ARCH_PFN_OFFSET))
   9: #define __page_to_pfn(page)    ((unsigned long)((page) - mem_map) + \
  10:                  ARCH_PFN_OFFSET)
  11: #elif defined(CONFIG_DISCONTIGMEM)
  12:  
  13: #define __pfn_to_page(pfn)            \
  14: ({    unsigned long __pfn = (pfn);        \
  15:     unsigned long __nid = arch_pfn_to_nid(__pfn);  \
  16:     NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\
  17: })
  18:  
  19: #define __page_to_pfn(pg)                        \
  20: ({    struct page *__pg = (pg);                    \
  21:     struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg));    \
  22:     (unsigned long)(__pg - __pgdat->node_mem_map) +            \
  23:      __pgdat->node_start_pfn;                    \
  24: })
  25:  
  26: #elif defined(CONFIG_SPARSEMEM_VMEMMAP)
  27:  
  28: /* memmap is virtually contiguous.  */
  29: #define __pfn_to_page(pfn)    (vmemmap + (pfn))
  30: #define __page_to_pfn(page)    (unsigned long)((page) - vmemmap)
  31:  
  32: #elif defined(CONFIG_SPARSEMEM)
  33: /*
  34:  * Note: section's mem_map is encorded to reflect its start_pfn.
  35:  * section[i].section_mem_map == mem_map's address - start_pfn;
  36:  */
  37: #define __page_to_pfn(pg)                    \
  38: ({    struct page *__pg = (pg);                \
  39:     int __sec = page_to_section(__pg);            \
  40:     (unsigned long)(__pg - __section_mem_map_addr(__nr_to_section(__sec)));    \
  41: })
  42:  
  43: #define __pfn_to_page(pfn)                \
  44: ({    unsigned long __pfn = (pfn);            \
  45:     struct mem_section *__sec = __pfn_to_section(__pfn);    \
  46:     __section_mem_map_addr(__sec) + __pfn;        \
  47: })
  48: #endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */
  49:  
  50: #define page_to_pfn __page_to_pfn
  51: #define pfn_to_page __pfn_to_page

페이지 구조 체
   1: /*
   2:  * Each physical page in the system has a struct page associated with
   3:  * it to keep track of whatever it is we are using the page for at the
   4:  * moment. Note that we have no way to track which tasks are using
   5:  * a page, though if it is a pagecache page, rmap structures can tell us
   6:  * who is mapping it.
   7:  */
   8: struct page {
   9:     unsigned long flags;        /* Atomic flags, some possibly
  10:                      * updated asynchronously */
  11:     atomic_t _count;        /* Usage count, see below. */
  12:     union {
  13:         /*
  14:          * Count of ptes mapped in
  15:          * mms, to show when page is
  16:          * mapped & limit reverse map
  17:          * searches.
  18:          *
  19:          * Used also for tail pages
  20:          * refcounting instead of
  21:          * _count. Tail pages cannot
  22:          * be mapped and keeping the
  23:          * tail page _count zero at
  24:          * all times guarantees
  25:          * get_page_unless_zero() will
  26:          * never succeed on tail
  27:          * pages.
  28:          */
  29:         atomic_t _mapcount;
  30:  
  31:         struct {        /* SLUB */
  32:             u16 inuse;
  33:             u16 objects;
  34:         };
  35:     };
  36:     union {
  37:         struct {
  38:         unsigned long private;        /* Mapping-private opaque data:
  39:                           * usually used for buffer_heads
  40:                          * if PagePrivate set; used for
  41:                          * swp_entry_t if PageSwapCache;
  42:                          * indicates order in the buddy
  43:                          * system if PG_buddy is set.
  44:                          */
  45:         struct address_space *mapping;    /* If low bit clear, points to
  46:                          * inode address_space, or NULL.
  47:                          * If page mapped as anonymous
  48:                          * memory, low bit is set, and
  49:                          * it points to anon_vma object:
  50:                          * see PAGE_MAPPING_ANON below.
  51:                          */
  52:         };
  53: #if USE_SPLIT_PTLOCKS
  54:         spinlock_t ptl;
  55: #endif
  56:         struct kmem_cache *slab;    /* SLUB: Pointer to slab */
  57:         struct page *first_page;    /* Compound tail pages */
  58:     };
  59:     union {
  60:         pgoff_t index;        /* Our offset within mapping. */
  61:         void *freelist;        /* SLUB: freelist req. slab lock */
  62:     };
  63:     struct list_head lru;        /* Pageout list, eg. active_list
  64:                      * protected by zone->lru_lock !
  65:                      */
  66:     /*
  67:      * On machines where all RAM is mapped into kernel address space,
  68:      * we can simply calculate the virtual address. On machines with
  69:      * highmem some memory is mapped into kernel virtual memory
  70:      * dynamically, so we need a place to store that address.
  71:      * Note that this field could be 16 bits on x86 ... ;)
  72:      *
  73:      * Architectures with slow multiplication can define
  74:      * WANT_PAGE_VIRTUAL in asm/page.h
  75:      */
  76: #if defined(WANT_PAGE_VIRTUAL)
  77:     void *virtual;            /* Kernel virtual address (NULL if
  78:                        not kmapped, ie. highmem) */
  79: #endif /* WANT_PAGE_VIRTUAL */
  80: #ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
  81:     unsigned long debug_flags;    /* Use atomic bitops on this */
  82: #endif
  83:  
  84: #ifdef CONFIG_KMEMCHECK
  85:     /*
  86:      * kmemcheck wants to track the status of each byte in a page; this
  87:      * is a pointer to such a status block. NULL if not tracked.
  88:      */
  89:     void *shadow;
  90: #endif
  91: };

1. flags, 현재 페이지 의 상 태 를 정의 하 는 enum 변 수 는 현재 페이지 가 있 는 zone 번호 (also encodes the zone number to which the page frame belongs) 도 저장 합 니 다.
그 중 각 상태의 정 의 는 다음 과 같다.
   1: enum pageflags {
   2:     PG_locked,        /* Page is locked. Don't touch. */
   3:     PG_error,
   4:     PG_referenced,
   5:     PG_uptodate,
   6:     PG_dirty,
   7:     PG_lru,
   8:     PG_active,
   9:     PG_slab,
  10:     PG_owner_priv_1,    /* Owner use. If pagecache, fs may use*/
  11:     PG_arch_1,
  12:     PG_reserved,
  13:     PG_private,        /* If pagecache, has fs-private data */
  14:     PG_private_2,        /* If pagecache, has fs aux data */
  15:     PG_writeback,        /* Page is under writeback */
  16: #ifdef CONFIG_PAGEFLAGS_EXTENDED
  17:     PG_head,        /* A head page */
  18:     PG_tail,        /* A tail page */
  19: #else
  20:     PG_compound,        /* A compound page */
  21: #endif
  22:     PG_swapcache,        /* Swap page: swp_entry_t in private */
  23:     PG_mappedtodisk,    /* Has blocks allocated on-disk */
  24:     PG_reclaim,        /* To be reclaimed asap */
  25:     PG_swapbacked,        /* Page is backed by RAM/swap */
  26:     PG_unevictable,        /* Page is "unevictable"  */
  27: #ifdef CONFIG_MMU
  28:     PG_mlocked,        /* Page is vma mlocked */
  29: #endif
  30: #ifdef CONFIG_ARCH_USES_PG_UNCACHED
  31:     PG_uncached,        /* Page has been mapped as uncached */
  32: #endif
  33: #ifdef CONFIG_MEMORY_FAILURE
  34:     PG_hwpoison,        /* hardware poisoned page. Don't touch */
  35: #endif
  36: #ifdef CONFIG_TRANSPARENT_HUGEPAGE
  37:     PG_compound_lock,
  38: #endif
  39:     __NR_PAGEFLAGS,
  40:  
  41:     /* Filesystems */
  42:     PG_checked = PG_owner_priv_1,
  43:  
  44:     /* Two page bits are conscripted by FS-Cache to maintain local caching
  45:      * state.  These bits are set on pages belonging to the netfs's inodes
  46:      * when those inodes are being locally cached.
  47:      */
  48:     PG_fscache = PG_private_2,    /* page backed by cache */
  49:  
  50:     /* XEN */
  51:     PG_pinned = PG_owner_priv_1,
  52:     PG_savepinned = PG_dirty,
  53:  
  54:     /* SLOB */
  55:     PG_slob_free = PG_private,
  56:  
  57:     /* SLUB */
  58:     PG_slub_frozen = PG_active,
  59: };

그 중에서 커 널 은 조작 하기에 편리 한 매크로 를 정의 합 니 다.
   1: PageXXX()
   2:  
   3: SetPageXXX()
   4:  
   5: ClearPageXXX()

각각 상태 위 치 를 조회, 설정, 제거 하 는 데 사 용 됩 니 다.
2. _count, 인용 계수
   1: page_count()

인용 수 를 조회 하 는 데 사용 할 수 있 습 니 다.
 
The pool of Reserved Page Frames
보류 페이지 할당 풀
 
메모리 페이지 를 할당 할 때 두 가지 상태 가 발생 할 수 있 습 니 다.
1. 남 은 메모리 페이지 가 충분 하고 분배 가 즉시 성공 합 니 다.
2. 남 은 메모리 페이지 가 부족 합 니 다. 메모리 회수 (Memory Reclaiming) 를 해 야 합 니 다. 메모리 페이지 를 신청 하 는 커 널 제어 경로 (Kernel Control Path) 는 남 은 메모리 페이지 가 나타 날 때 까지 block 되 어야 합 니 다.
 
그러나 일부 Kernel Control Path 는 block 되 어 서 는 안 됩 니 다. 예 를 들 어:
1. 중 단 된 Handler 처리 중;
2. 관건 구역 에 있 는 코드 (Critical Section)
이 Kernel Control Path 는 메모리 페이지 를 신청 할 때 GFP 를 사용 해 야 합 니 다.ATOMIC 로 고 는 신청 이 block 에 의 해 이 루어 져 서 는 안 된다 는 것 을 나타 내 며 충분 한 메모리 페이지 가 없 으 면 바로 실패 하고 돌아 갑 니 다.
 
하지만 내 핵 은 가능 한 한 GFP 를 확보 해 야 합 니 다.ATOMIC 유형의 신청 은 정확하게 실 행 될 수 있 기 때문에 커 널 은 물리 적 메모리 페이지 를 일정 수량의 보존 하고 있 습 니 다. 이 메모리 페이지 는 저 메모리 상태 (Low - On - Memory) 조건 에서 만 GFP 를 제공 합 니 다.ATOMIC 사용.
 
보통 minfree_kbytes (이렇게 많은 KB) 의 메모 리 를 Pool 로 사용 합 니 다.
공식 을 통과 하 다
   1: reserved_pool_size = floor(sqrt(16 * (ZONE_DMA + ZONE_NORMAL)))

계산 하고 128 ∼ 65536 KB 로 제한한다.
그리고 크기 에 따라 ZONE 에서DMA 및 ZONENORMAL 간 에 각자 보유 한 비율 을 분배 하 다.
 
Linux 커 널 이 직접 매 핑 할 수 있 는 선형 주소 범 위 는 3GB ~ 3GB + 896 MB 이다.
이 범위 내 물리 메모리 페이지 를 할당 하면 분 배 된 페이지 의 선형 메모리 주 소 를 직접 되 돌려 줄 수 있 습 니 다.그러나 분 배 된 물리 적 메모리 가 이 범위 내 에 있 지 않 으 면 해당 하 는 커 널 공간의 선형 주 소 를 직접 되 돌 릴 수 없 지만 페이지 구조 체 (struct page) 의 주 소 를 되 돌 릴 수 있 습 니 다. 모든 물리 적 메모리 페이지 의 페이지 구조 체 는 mem 에 저장 되 어 있 기 때 문 입 니 다.맵 중.
 
이러한 방식 의 제한 은 선형 주소 공간 3GB ~ 3GB + 896 MB 범위 밖의 메모 리 를 할당 할 경우 이 물리 적 메모리 페이지 를 선형 주소 의 맵 으로 다시 업데이트 해 야 한 다 는 것 이다. 즉, 페이지 표를 다시 설정 하 는 것 이다.
페이지 시트 에 대한 추가 작업 으로 인해 이 메모리 들 을 분배 하 는 것 이 고정 맵 의 그 부분 메모 리 를 분배 하 는 것 보다 효율 적 입 니 다.
 
고급 메모리 맵 참조:http://linux.chinaitlab.com/administer/831348.html
다음으로 전송:https://www.cnblogs.com/long123king/p/3497445.html

좋은 웹페이지 즐겨찾기