元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
进程管理
▶
进程调度
调度策略
完全公平调度器
实时调度机制
▶
进程通信
信号机制
共享内存
管道与命名管道
▶
进程状态
上下文切换
僵尸进程处理
进程生命周期
▶
内存管理
▶
虚拟内存
页表机制
地址空间布局
TLB管理
▶
物理内存
伙伴系统
slab分配器
内存碎片处理
▶
文件系统
▶
VFS抽象层
inode机制
文件描述符
挂载机制
▶
具体文件系统
Ext4日志机制
Btrfs特性
Proc文件系统
▶
设备驱动
▶
驱动模型
设备树解析
sysfs接口
热插拔处理
▶
网络栈
▶
协议栈架构
sk_buff结构
Netfilter框架
套接字实现
▶
内核同步机制
▶
锁机制
自旋锁实现
RCU机制
Mutex与信号量
▶
启动过程
▶
引导阶段
GRUB交互
内核解压缩
早期初始化
▶
系统调用
▶
调用机制
陷入门实现
vsyscall优化
安全审计
▶
虚拟化和容器支持
▶
容器技术
命名空间隔离
cgroups实现
OverlayFS原理
发布时间:
2025-03-23 10:46
↑
☰
# Linux内存碎片处理详解 内存碎片是Linux系统中的一个常见问题,它会导致内存利用率降低,影响系统性能。本文将详细介绍Linux系统中的内存碎片处理机制。 ## 基本概念 ### 碎片类型 1. 内部碎片 - 由于分配单元大小固定导致的内存浪费 - 例如:分配4KB页面来存储3KB数据 - 主要发生在页面级别分配中 2. 外部碎片 - 空闲内存块不连续导致的浪费 - 无法满足大内存分配请求 - 主要发生在伙伴系统中 ### 碎片度量 1. 碎片指标 ```c // 外部碎片率 fragmentation_index = 1 - (largest_free_block_size / total_free_memory); // 内部碎片率 internal_fragmentation = (allocated_size - used_size) / allocated_size; ``` 2. 监控工具 ```bash # 查看内存碎片信息 cat /proc/buddyinfo # 查看内存使用统计 cat /proc/meminfo ``` ## 碎片防治 ### 分配策略 1. 首次适配 ```c static unsigned long find_first_fit(unsigned long size, unsigned long align, unsigned long flags) { struct vm_struct *area; // 遍历空闲区域链表 list_for_each_entry(area, &vmap_area_list, list) { unsigned long addr; // 检查区域大小 if (area->size < size) continue; // 检查对齐要求 addr = ALIGN(area->addr, align); if (addr + size <= area->addr + area->size) return addr; } return 0; } ``` 2. 最佳适配 ```c static unsigned long find_best_fit(unsigned long size, unsigned long align, unsigned long flags) { struct vm_struct *area; unsigned long best_addr = 0; unsigned long best_size = ~0UL; // 遍历查找最合适的区域 list_for_each_entry(area, &vmap_area_list, list) { unsigned long addr; if (area->size < size) continue; addr = ALIGN(area->addr, align); if (addr + size <= area->addr + area->size) { if (area->size < best_size) { best_addr = addr; best_size = area->size; } } } return best_addr; } ``` ### 合并策略 1. 相邻页面合并 ```c static inline void __free_one_page(struct page *page, unsigned long pfn, struct zone *zone, unsigned int order, int migratetype) { unsigned long buddy_pfn; unsigned long combined_pfn; struct page *buddy; // 循环合并伙伴页面 while (order < MAX_ORDER-1) { buddy_pfn = find_buddy_pfn(pfn, order); buddy = page + (buddy_pfn - pfn); // 检查伙伴是否可合并 if (!page_is_buddy(page, buddy, order)) break; // 合并页面 list_del(&buddy->lru); zone->free_area[order].nr_free--; combined_pfn = buddy_pfn & pfn; page = page + (combined_pfn - pfn); pfn = combined_pfn; order++; } } ``` 2. 内存规整 ```c int compact_zone(struct zone *zone, struct compact_control *cc) { unsigned long migrate_pfn, free_pfn; // 初始化迁移和空闲页面指针 migrate_pfn = zone->zone_start_pfn; free_pfn = zone_end_pfn(zone); // 迁移页面填充空洞 while (migrate_pfn < free_pfn) { // 查找可迁移页面 if (!migratepage_isolate(zone, migrate_pfn)) { migrate_pfn++; continue; } // 查找空闲页面 free_pfn = find_suitable_fallback(zone, free_pfn); // 执行页面迁移 if (migrate_page(zone, migrate_pfn, free_pfn)) { migrate_pfn++; free_pfn--; } } return 0; } ``` ## 内存规整 ### 页面迁移 1. 迁移类型 ```c enum migratetype { MIGRATE_UNMOVABLE, // 不可移动 MIGRATE_MOVABLE, // 可移动 MIGRATE_RECLAIMABLE, // 可回收 MIGRATE_PCPTYPES, // per-cpu类型 MIGRATE_TYPES // 类型数量 }; ``` 2. 迁移函数 ```c int migrate_pages(struct list_head *from, struct list_head *to, new_page_t get_new_page, free_page_t put_new_page, unsigned long private, enum migrate_mode mode, int reason) { int retry = 1; int nr_failed = 0; int nr_succeeded = 0; int pass = 0; struct page *page; struct page *page2; // 迁移页面 while (retry) { retry = 0; list_for_each_entry_safe(page, page2, from, lru) { if (!migrate_page(get_new_page, put_new_page, private, page, mode)) { nr_succeeded++; } else { nr_failed++; } } pass++; if (pass > 2) break; retry = nr_failed; } return nr_failed; } ``` ### 内存压缩 1. 压缩控制 ```c struct compact_control { struct list_head freepages; // 空闲页面链表 struct list_head migratepages; // 待迁移页面链表 unsigned long nr_freepages; // 空闲页面数 unsigned long nr_migratepages; // 待迁移页面数 unsigned long free_pfn; // 空闲页面指针 unsigned long migrate_pfn; // 迁移页面指针 bool sync; // 同步标志 }; ``` 2. 压缩执行 ```c int compact_zone(struct zone *zone, struct compact_control *cc) { unsigned long start_pfn; unsigned long end_pfn; // 初始化范围 start_pfn = zone->zone_start_pfn; end_pfn = zone_end_pfn(zone); // 扫描待迁移页面 isolate_migratepages_range(zone, cc, start_pfn, end_pfn); // 扫描空闲页面 isolate_freepages_range(zone, cc, start_pfn, end_pfn); // 执行迁移 migrate_pages(&cc->migratepages, &cc->freepages, alloc_migration_target, NULL, 0, MIGRATE_SYNC, MR_MEMORY_COMPACT); // 释放未迁移的页面 putback_movable_pages(&cc->migratepages); return 0; } ``` ## 碎片优化 ### 预防措施 1. 分配优化 ```c // 使用大页内存 void *alloc_large_system_hash(const char *tablename, unsigned long bucketsize, unsigned long numentries, int scale, int flags, unsigned int *_hash_shift, unsigned int *_hash_mask, unsigned long low_limit, unsigned long high_limit) { unsigned long log2qty; void *table = NULL; // 计算大小 log2qty = ilog2(numentries) + scale; // 分配大页内存 table = __get_free_pages(GFP_ATOMIC, get_order(bucketsize)); return table; } ``` 2. 内存对齐 ```c void *kmalloc_aligned(size_t size, unsigned int align) { void *ptr = NULL; // 分配对齐内存 if (align < sizeof(void *)) align = sizeof(void *); ptr = (void *)__get_free_pages(GFP_KERNEL, get_order(size)); if (ptr) { ptr = (void *)ALIGN((unsigned long)ptr, align); } return ptr; } ``` ### 监控和调优 1. 系统参数 ```bash # 设置内存压缩阈值 echo 1 > /proc/sys/vm/compact_memory # 调整kswapd唤醒阈值 echo 60 > /proc/sys/vm/watermark_scale_factor ``` 2. 性能监控 ```bash # 查看内存碎片统计 cat /proc/buddyinfo # 查看内存压缩统计 cat /proc/vmstat | grep compact # 使用perf工具分析 perf record -g -a sleep 10 perf report ``` ## 最佳实践 1. 内存分配 - 使用合适的页面大小 - 注意内存对齐 - 避免频繁分配释放 2. 碎片处理 - 定期执行内存压缩 - 合理设置迁移类型 - 监控碎片状况 3. 系统优化 - 使用大页内存 - 调整系统参数 - 及时回收内存 ## 总结 内存碎片是Linux系统中不可避免的问题,但通过合理的分配策略、及时的碎片整理和有效的监控手段,我们可以将其影响降到最低。理解内存碎片的产生原因和处理机制对于开发高性能的Linux应用程序和进行系统优化非常重要。在实际应用中,我们应该采取预防措施避免碎片产生,同时通过内存规整等手段及时处理已产生的碎片。