Linux struct page 的雙字對齊設計思想
?
1.雙字對齊(8字節對齊):
?
?確保struct page的大小是sizeof(long)的整數倍(通常8字節),便于CPU高效訪問。
?
?減少內存碎片,提高緩存行(Cache Line)利用率。
?
2.聯合體(union)復用字段:
?
?不同場景(如匿名頁、文件頁、Slab頁等)共用同一存儲空間。
?
?例如:mapping字段既可能指向address_space(文件頁),也可能指向匿名頁的anon_vma。
?
3.標志位壓縮:
?
?使用flags的高位存儲頁狀態(如PG_locked、PG_dirty),低位存儲區信息(如zone_id)。
?
4.引用計數與映射計數分離:
?
?_refcount記錄物理頁的引用數,_mapcount記錄頁表映射數。
?
?
類似結構體設計示例
?
以下是一個模仿struct page設計的簡化結構體,用于管理自定義內存對象(如用戶態內存池的塊):
?
#include <linux/types.h>
#include <linux/mm_types.h>
?
struct my_mem_chunk {
? ? // --- 雙字1: 標志和狀態 ---
? ? unsigned long flags; // 狀態標志(對齊到8字節)
? ??
? ? // --- 雙字2: 聯合體復用字段 ---
? ? union {
? ? ? ? struct list_head lru; // LRU鏈表(用于緩存)
? ? ? ? struct {
? ? ? ? ? ? void *virtual; // 虛擬地址(內核映射用)
? ? ? ? ? ? atomic_t _refcount; // 引用計數
? ? ? ? };
? ? ? ? struct {
? ? ? ? ? ? unsigned long private; // 私有數據(如所有者ID)
? ? ? ? ? ? struct address_space *mapping; // 關聯的地址空間
? ? ? ? };
? ? };
?
? ? // --- 雙字3: 類型相關數據 ---
? ? union {
? ? ? ? unsigned long _mapcount; // 映射計數(類似page_mapcount)
? ? ? ? void *freelist; // 空閑鏈表(Slab用)
? ? ? ? struct {
? ? ? ? ? ? unsigned int obj_size; // 對象大小
? ? ? ? ? ? unsigned int obj_type; // 對象類型
? ? ? ? };
? ? };
?
? ? // --- 雙字4: 預留擴展 ---
? ? u64 extended[1]; // 保留未來擴展
} __attribute__((aligned(8))); // 強制8字節對齊
?
?
關鍵設計點解析
?
1.雙字對齊強制:
?
?使用__attribute__((aligned(8)))確保結構體起始地址和大小均為8字節對齊。
?
2.聯合體復用:
?
?字段復用:lru鏈表、虛擬地址virtual和mapping共享同一存儲空間。
?
?場景區分:
?
? 緩存管理場景:使用lru鏈表。
?
? 內核映射場景:使用virtual和_refcount。
?
? 文件關聯場景:使用mapping和private。
?
3.標志位設計(flags):
?
?模仿Linux的page-flags.h,可通過位掩碼定義狀態:
?
?#define MY_CHUNK_LOCKED 0x00000001 // 塊已鎖定
?#define MY_CHUNK_DIRTY 0x00000002 // 塊已修改
?#define MY_CHUNK_TYPE_MASK 0x0000000C // 類型掩碼(2位)
?
4.引用計數與映射計數:
?
?_refcount:原子操作確保線程安全。
?
?_mapcount:記錄塊被映射的次數(如共享內存)。?
?
使用場景示例
?
場景1:用戶態內存池分配?
?
struct my_mem_chunk *chunk = alloc_chunk();
chunk->flags |= MY_CHUNK_LOCKED;
chunk->virtual = user_vaddr;
atomic_set(&chunk->_refcount, 1);
?
場景2:文件緩存
?
struct my_mem_chunk *chunk = get_cached_chunk();
chunk->mapping = file->f_mapping;
chunk->private = (unsigned long)file;
?
場景3:Slab分配器
?
struct my_mem_chunk *chunk = slab_alloc();
chunk->freelist = next_free_obj;
chunk->obj_size = size;
?
性能優化點
?
1.緩存行友好:
?
?將高頻訪問字段(如flags、_refcount)放在結構體頭部。
?
2.原子操作優化:
?
?_refcount使用atomic_t避免鎖競爭。
?
3.內存壓縮:
?
?通過聯合體將結構體大小控制在32字節(4個雙字),接近Linux的struct page(通常40字節)。
?
對比Linux的struct page
?
特性 Linux struct page 本設計 my_mem_chunk
?
對齊方式 8字節對齊 顯式8字節對齊
?
核心字段 flags, mapping, _refcount flags, 聯合體, _refcount
?
多場景支持 匿名頁、文件頁、Slab等 內存池、緩存、Slab等
?
大小 40字節(典型) 32字節(可擴展)?
?
通過這種設計,既能復用Linux內存管理的核心思想,又能根據實際需求靈活調整字段,適用于高密度內存管理的場景。?