当前位置: 首页 > news >正文

Linux内核中的内存管理详解

Linux内核中的内存管理详解

引言

内存管理是Linux内核中最核心、最复杂的组件之一,它负责管理系统的物理内存,为进程提供虚拟地址空间,确保内存资源的高效利用和系统的稳定性。Linux内核的内存管理支持多种特性,包括虚拟内存、分页、交换、缓存等,同时提供了丰富的内存分配机制,如slab分配器、伙伴系统等。本文将深入探讨Linux内核中的内存管理,包括其设计原理、架构、核心机制和应用场景。

内存管理的基本概念

1. 物理内存与虚拟内存

  • 物理内存:计算机中实际的RAM(随机存取存储器)
  • 虚拟内存:操作系统为每个进程提供的独立地址空间
  • 虚拟地址:进程使用的地址
  • 物理地址:物理内存的实际地址

2. 地址空间

  • 用户空间:进程可以访问的地址空间
  • 内核空间:内核专用的地址空间
  • 32位系统:地址空间4GB,用户空间3GB,内核空间1GB
  • 64位系统:地址空间更大,用户空间和内核空间的分配更加灵活

3. 分页机制

  • :内存管理的基本单位,通常是4KB
  • 页表:记录虚拟页到物理页的映射
  • 页表项:页表中的条目,记录映射信息
  • 页目录:多级页表结构中的上一级

虚拟内存管理

1. 地址空间布局

// 32位系统地址空间布局// 0x00000000 - 0xBFFFFFFF:用户空间(3GB)// 0xC0000000 - 0xFFFFFFFF:内核空间(1GB)// 64位系统地址空间布局(x86_64)// 0x0000000000000000 - 0x00007FFFFFFFFFFF:用户空间// 0xFFFF800000000000 - 0xFFFFFFFFFFFFFFFF:内核空间

2. 内存描述符

mm_struct结构体描述进程的地址空间。

structmm_struct{structvm_area_struct*mmap;structrb_rootmm_rb;structvm_area_struct*mmap_cache;unsignedlong(*get_unmapped_area)(structfile*filp,unsignedlongaddr,unsignedlonglen,unsignedlongpgoff,unsignedlongflags);void(*unmap_area)(structmm_struct*mm,unsignedlongaddr);unsignedlongmmap_base;unsignedlongmmap_legacy_base;unsignedlongtask_size;unsignedlonghighest_vm_end;pgd_t*pgd;atomic_tmm_users;atomic_tmm_count;intmap_count;spinlock_tpage_table_lock;structrw_semaphoremmap_sem;// 其他字段...};

3. 虚拟内存区域

vm_area_struct结构体描述进程的虚拟内存区域。

structvm_area_struct{structmm_struct*vm_mm;unsignedlongvm_start;unsignedlongvm_end;structvm_area_struct*vm_next,*vm_prev;pgprot_tvm_page_prot;unsignedlongvm_flags;structrb_nodevm_rb;// 其他字段...};

页表管理

1. 页表结构

Linux使用多级页表来管理虚拟地址到物理地址的映射。

// 4级页表(x86_64)// PGD(Page Global Directory)// PUD(Page Upper Directory)// PMD(Page Middle Directory)// PTE(Page Table Entry)

2. 页表操作

// 设置页表项set_pte(pte_t*ptep,pte_tpte);// 清除页表项pte_clear(structmm_struct*mm,unsignedlongaddr,pte_t*ptep);// 检查页表项是否存在pte_present(pte_tpte);

3. TLB(转换后援缓冲器)

TLB是一种硬件缓存,用于加速虚拟地址到物理地址的转换。

// 刷新TLBflush_tlb_all();flush_tlb_mm(structmm_struct*mm);flush_tlb_page(structvm_area_struct*vma,unsignedlongpage);

物理内存管理

1. 页帧

物理内存被分成固定大小的页帧,通常是4KB。

structpage{unsignedlongflags;atomic_t_count;atomic_t_mapcount;unsignedlongprivate;structaddress_space*mapping;pgoff_tindex;structlist_headlru;// 其他字段...};

2. 伙伴系统

伙伴系统用于管理物理页帧的分配和释放。

// 分配页structpage*alloc_pages(gfp_tgfp_mask,unsignedintorder);// 分配单页structpage*alloc_page(gfp_tgfp_mask);// 释放页void__free_pages(structpage*page,unsignedintorder);

3. 内存节点与区域

Linux将物理内存分成多个节点和区域。

// 内存节点typedefstructpglist_data{structzonenode_zones[MAX_NR_ZONES];structzonelistnode_zonelists[MAX_ZONELISTS];intnr_zones;// 其他字段...}pg_data_t;// 内存区域structzone{unsignedlongwatermark[NR_WMARK];unsignedlonglowmem_reserve[MAX_NR_ZONES];structper_cpu_pageset__percpu*pageset;spinlock_tlock;// 其他字段...};

内存分配

1. 页分配

// 分配页structpage*alloc_pages(gfp_tgfp_mask,unsignedintorder);// 分配单页structpage*alloc_page(gfp_tgfp_mask);// 获取页的虚拟地址void*page_address(structpage*page);// 释放页void__free_pages(structpage*page,unsignedintorder);

2. kmalloc

kmalloc用于分配小块内存,大小通常不超过页大小。

#include<linux/slab.h>// 分配内存void*kmalloc(size_tsize,gfp_tflags);// 释放内存voidkfree(constvoid*objp);

3. vmalloc

vmalloc用于分配大块内存,可以分配多个连续的虚拟页。

#include<linux/vmalloc.h>// 分配内存void*vmalloc(unsignedlongsize);// 释放内存voidvfree(constvoid*addr);

4. gfp标志

// 常用gfp标志GFP_KERNEL// 普通内核内存分配GFP_ATOMIC// 原子内存分配,不能睡眠GFP_USER// 用户内存分配GFP_HIGHUSER// 高端内存分配GFP_DMA// DMA内存分配

Slab分配器

1. Slab的概念

Slab分配器是Linux内核中用于管理小块内存分配的机制,它预分配一些内存块,然后从这些内存块中分配给需要的对象。

2. 创建Slab缓存

#include<linux/slab.h>// 创建slab缓存structkmem_cache*kmem_cache_create(constchar*name,size_tsize,size_talign,unsignedlongflags,void(*ctor)(void*));// 销毁slab缓存voidkmem_cache_destroy(structkmem_cache*cachep);

3. 从Slab缓存分配对象

// 分配对象void*kmem_cache_alloc(structkmem_cache*cachep,gfp_tflags);// 释放对象voidkmem_cache_free(structkmem_cache*cachep,void*objp);

页面缓存

1. 页面缓存的概念

页面缓存是Linux内核中用于缓存文件数据的机制,它将文件数据缓存在内存中,提高文件访问速度。

2. address_space

address_space结构体管理文件的页面缓存。

structaddress_space{structinode*host;structradix_tree_rootpage_tree;spinlock_ttree_lock;unsignedinti_mmap_writable;structprio_tree_rooti_mmap;structlist_headi_mmap_nonlinear;spinlock_ti_mmap_lock;atomic_ttruncate_count;// 其他字段...};

3. 页面缓存操作

// 查找页面structpage*find_get_page(structaddress_space*mapping,pgoff_toffset);// 添加页面intadd_to_page_cache_locked(structpage*page,structaddress_space*mapping,pgoff_toffset,gfp_tgfp_mask);// 读取页面intread_cache_page(structaddress_space*mapping,pgoff_tindex,int(*filler)(void*,structpage*),void*data);

交换(Swapping)

1. 交换的概念

交换是Linux内核中用于将不常用的内存页写入磁盘,以释放物理内存的机制。

2. 交换空间

交换空间是磁盘上的一块区域,用于存储换出的内存页。

# 创建交换文件ddif=/dev/zeroof=/swapfilebs=1Mcount=1024chmod600/swapfilemkswap/swapfileswapon/swapfile# 查看交换空间swapon-scat/proc/swaps

3. 页面换出

Linux使用LRU(最近最少使用)算法选择要换出的页面。

// 页面回收inttry_to_free_pages(structzonelist*zonelist,intorder,gfp_tgfp_mask);

实际案例分析

案例:使用kmalloc分配内存

#include<linux/module.h>#include<linux/kernel.h>#include<linux/init.h>#include<linux/slab.h>staticvoid*my_buffer;staticint__initmymem_init(void){// 分配内存my_buffer=kmalloc(1024,GFP_KERNEL);if(!my_buffer){printk(KERN_ERR"mymem: failed to allocate memory\n");return-ENOMEM;}printk(KERN_INFO"mymem: memory allocated at %p\n",my_buffer);return0;}staticvoid__exitmymem_exit(void){// 释放内存if(my_buffer){kfree(my_buffer);printk(KERN_INFO"mymem: memory freed\n");}}module_init(mymem_init);module_exit(mymem_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Your Name");MODULE_DESCRIPTION("kmalloc example");

案例:使用slab缓存

#include<linux/module.h>#include<linux/kernel.h>#include<linux/init.h>#include<linux/slab.h>structmy_struct{intdata1;chardata2[64];};staticstructkmem_cache*my_cache;staticstructmy_struct*my_obj;staticint__initmyslab_init(void){// 创建slab缓存my_cache=kmem_cache_create("my_cache",sizeof(structmy_struct),0,SLAB_HWCACHE_ALIGN,NULL);if(!my_cache){printk(KERN_ERR"myslab: failed to create cache\n");return-ENOMEM;}// 分配对象my_obj=kmem_cache_alloc(my_cache,GFP_KERNEL);if(!my_obj){printk(KERN_ERR"myslab: failed to allocate object\n");kmem_cache_destroy(my_cache);return-ENOMEM;}// 使用对象my_obj->data1=42;strcpy(my_obj->data2,"Hello, slab!");printk(KERN_INFO"myslab: object created, data1 = %d, data2 = %s\n",my_obj->data1,my_obj->data2);return0;}staticvoid__exitmyslab_exit(void){// 释放对象if(my_obj){kmem_cache_free(my_cache,my_obj);}// 销毁缓存if(my_cache){kmem_cache_destroy(my_cache);}printk(KERN_INFO"myslab: exit\n");}module_init(myslab_init);module_exit(myslab_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Your Name");MODULE_DESCRIPTION("slab example");

结论

Linux内核的内存管理是一个功能强大、设计复杂的系统,它为进程提供了虚拟地址空间,管理着物理内存的分配和回收,确保了内存资源的高效利用和系统的稳定性。通过深入了解Linux内存管理的架构、核心机制和实现原理,我们可以更好地理解和优化内存使用,提高系统的性能和可靠性。

在实际应用中,我们需要根据场景选择合适的内存分配方式,合理设计内存使用方案,避免内存泄漏和内存溢出。作为系统开发者和内核工程师,掌握内存管理的知识是非常重要的,它将帮助我们更好地设计和实现系统软件,解决内存相关的问题,提高系统的性能和稳定性。

http://www.jsqmd.com/news/615537/

相关文章:

  • OpenClaw+千问3.5-9B:个人财报自动分析与可视化
  • 嵌入式开发中的8种核心数据结构与优化策略
  • 2026年石英石优质产品推荐榜:岩石力石英石、岩石力、石英石选择指南 - 优质品牌商家
  • “INMS: Memory Sharing for Large Language Model based Agents“ 论文笔记夜
  • DHT温湿度传感器驱动库原理与工程实践
  • 百川2-13B-4bits量化版+OpenClaw:自动化周报生成与邮件发送
  • 【教程】2026年OpenClaw华为云7分钟搭建零门槛方法
  • MessagePack嵌入式C实现:面向mbed OS的轻量序列化方案
  • OpenClaw浏览器控制:Qwen3.5-9B自动填写网页表单
  • M5StickC-Plus嵌入式开发全指南:ESP32-PICO-D4硬件解析与低功耗实践
  • 大模型技术火爆!掌握RAG和代理,开启高薪AI职业生涯!
  • 2026年4月西安私立口腔医院推荐:家庭全科诊疗五家靠谱机构综合测评对比 - 品牌推荐
  • 红外遥控技术原理与应用详解
  • USB Type-C接口原理与PCB设计要点解析
  • C语言断言机制:原理、应用与调试技巧
  • Linux内核中的文件系统详解
  • OpenClaw云端体验方案:星图平台Qwen2.5-VL-7B镜像快速验证
  • 我不是在用 AI 助手,我在把自己的能力沉淀成组织资产囊
  • 基于File-Based App开发MVP项目钨
  • 简化 Python 代码以应对数据工程项目
  • 5个精准步骤:网络性能评估实战指南
  • OpenClaw浏览器插件:Phi-3-mini网页信息提取神器
  • PCB阻抗设计:高速电路信号完整性的关键
  • 大厂后端一面模拟:从线程安全到分布式缓存的连环追问
  • 毕业设计实战:基于Java+MySQL的直播电商交流平台设计与实现指南
  • 双碳引领:信息化赋能电力现货交易与新能源消纳工程实践
  • DDD难落地?就让AI干吧! - cleanddd-skills介绍儆
  • STM32裸机步进电机驱动库:ULN2003+高精度定时控制
  • 2026年OpenClaw如何集成?腾讯云1分钟喂奶级教程+大模型APIKey配置、Skill集成
  • Omdia:受社交视频广告推动,2030年全球在线视频和电视收入将超过1万亿美元