`
Michaelmatrix
  • 浏览: 219562 次
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Linux内存管理

 
阅读更多

本文首先介绍一下Linux内存管理方式,着重说明一下用户空间的内存管理,包括Linux虚拟映射以及GLIBC中malloc的实现;然后简要介绍单进程多线程的内存管理方式,主要涉及各线程堆栈空间的分配;

Linux 内存管理

Linux 采用两级保护机制,隔离内核空间和用户程序空间,使用户程序无法直接访问内核,而只能通过系统调用的方式。

对于 32 CPU 来说, Linux 虚拟内存空间大小为 4G ,其中内核占据 3G~4G 空间(依据 CPU 体系的不同而有差别),应用程序占据 0~3G 空间。其中用户空间又分为代码段、数据段、 BSS 、堆及栈空间,各段分布如图所示:

上图不连续部分,表示可能存在隔离空间。实际上在我虚拟机上的 Linux ,内核为 2.6.9 ,动态链接库是映射到低地址的 128M 空间里的,可网上众多资料都说其映射到堆栈之间,有待以后研究。下面就来分别介绍各部分内存空间。

内核空间

对于 X86 体系来说,内核占据高端 1G 虚拟内存,其中又分为两部分 linux 内核区域及 vmalloc 区域。

1. 内核区域

Linux 内核可以认为是实地址模式,物理地址经过简单的偏移即构成逻辑地址,即内核编程时,我们可以认为操作的是物理内存,并且这段内存是物理连续的。其中用到两种内存分配方式,整页分配(大内存)、 slab 分配(小内存)。

Linux 内核提供了比较完善的内存管理方式,页分配 _get_free_page ,基于 slab 的小内存分配 kmalloc 。这两个接口的实现都首先调用 __alloc_pages() ,分配物理页面,然后 kmalloc 在分配的物理页面上实现 slab 管理。分配物理页面基于 buddy 算法,在使用 buddy 实现的物理内存管理中最小分配粒度是以页为单位的,大小通常为 4K __alloc_pages() 函数中,多次尝试调用 get_page_from_freelist() 函数从 zonelist 中取得相关 zone ,并从其中返回一个可用的物理页面。

实际上,内核空间的起始地址是物理内存的低地址,内核有自己的页表,经过简单的偏移转换成逻辑地址,另外每个进程也都有自己的页表。

2. vmalloc

这个区域一般占据最高地址 128M 空间,也属于内核区域,不过它对应不连续的物理空间,这里的情况很类似于用户空间分配虚拟内存,内存逻辑上连续,其实映射到并不一定连续的物理内存上。 Linux 内核借用了这个技术,允许内核程序在内核地址空间中分配虚拟地址,同样也利用页表(内核页表)将虚拟地址映射到分散的内存页上。内核提供 vmalloc 函数分配内核虚拟内存,该函数不同于 kmalloc ,它可以分配较 Kmalloc 大得多的内存空间(可远大于 128K ,但必须是页大小的倍数),但相比 Kmalloc 来说 ,Vmalloc 需要对内核虚拟地址进行重映射,必须更新内核页表,因此分配效率上要低一些(用空间换时间)。

用户空间

当应用程序以 elf 格式被加载时, Linux 加载器首先将其加载到 0X0804 8000 处,对 X86 PPC 来说, 0X0804 8000~0XC000 0000 这段地址空间才是程序可用的,任何访问到这个范围以外的指令,都会引起段错误。至于为什么 Linux 放着前 128M 内存空间不用, google 一下也没有搜索到答案,有待以后研究。

上面已经说过,每个进程都有自己的页表,记录着逻辑地址与物理页面的对应关系,当进程切换时,新进程页表首地址就被加载到 CR3 寄存器中,内存的访问首先都是从 CR3 开始,找到 TLB (页表缓冲区),通过逻辑地址找出对应的物理页面。另外进程 PCB 中还有许多 vm_struct 指针,每个 vm_struct 记录着一段逻辑地址空间以及对应的操作函数,比如代码空间、栈空间、 mmap 映射空间等,不同的空间,其读写函数以及权限也是不一样的。这些结构体对应的逻辑空间都会有间隔,防止越界访问。

当发生缺页异常时,即访问的逻辑地址对应的物理页面还未映射,或是已经被交换出去时,异常处理程序首先找到这个逻辑地址对应的 vm_struct 。如果找不到对应的 vm_struct ,说明发生了非法访问,否则找到相应的 vm_struct ,查找这段逻辑地址对应的设备文件的地址,并应用结构体中注册的相关函数将其内容调入物理页面。

一般未发生缺页异常或重新映射到物理内存后,内存访问经过页表转换时,页表条目中相应的位代表访问该页的一系列权限,这时就会进行权限检查,做到内存保护。

关于栈空间与 mmap 映射动态链接库的空间,都是由内核管理的,在必要的时候也可以挪动 mmap 映射的位置,为栈的增长提供空间。这里我们主要讨论一下堆空间,即 malloc 内存,它是调用 brk 实现的。这个调用只是扩张堆空间边界,并不对应物理内存,只是在使用时,发生缺页异常后,才由内核映射物理内存。但是,并不是每次 malloc 都会引起 brk 调用, malloc 自身维护一个空闲链,用于收集堆空间上已经释放的空间,当然这个是逻辑地址空间。每次 malloc 调用,首先试图从该空闲链中获取该空间,当链上的元素都不能满足时,才会调用 brk ,扩张堆空间,以获得足够大的逻辑空间。每次 free 时,都会将释放的空间放入空闲链中,并检查该空间相邻的逻辑空间,如果也空闲,则合并为一块较大的空间。实际上 malloc 管理操作会比以上所说的更复杂,具体细节只有研究 glibc 的代码,网上并没有很好的资料。

所以, malloc 这种管理方式类似于 VxWorks 的 内存管理方式,如果频繁的申请、释放小内存,同样会在逻辑空间产生内存碎片。虽然对于不同的内存部分,其逻辑空间并不会连续(像栈空间和堆空间),但是堆 空间内部,通过malloc申请的内存仍然有可能发生越界,破坏本进程相邻的变量内存空间,不过这种越界比较容易定位,因为只是限于本进程内部。至于野指 针,其影响也只限于本进程,对系统和其它进程不会构成威胁。

Linux 线程库

线程最主要的目的就是更好地支持 SMP 以及减小进程上下文切换开销,针对这两大意义,分别开发了核心线程和用户级线程。 Linux 内核仅支持轻量级进程,所以 linux 下的线程库不可能实现完全意义上的 POSIX 线程机制,不能实现用户级调度,以减小切换开销。

Linux 线程库栈空间的分配,依据个 CPU 架构的不同而有所区别,这里只能分析 i386 平台所使用的两种栈组织方式: FLOATING_STACK 方式和用户自定义方式。

FLOATING_STACK 方式下, LinuxThreads 利用 mmap() 分配 8MB 空间( i386 系统缺省的最大栈空间大小,如果有运行限制( rlimit ),则按照运行限制设置),使用 mprotect() 设置其中第一页为非访问区。该 8M 空间的功能分配如下图:

低地址被保护的页面用来监测栈溢出。对于用户指定的栈,在按照指针对界后,设置线程栈顶,并计算出栈底,不做保护,正确性由用户自己保证,我想应该也可以调用 mprotect 设置隔离区域,监测堆栈溢出。不论哪种组织方式,线程描述结构总是位于栈顶紧邻堆栈的位置。

至于堆空间,和单线程分配的机制是一样的。

分享到:
评论

相关推荐

    linux内存管理实验报告

    Linux内存管理是操作系统的核心组成部分,它负责有效地分配和回收内存资源,确保系统高效稳定地运行。在本实验中,我们主要探讨了Linux虚拟内存管理的原理、动态内存操作函数的使用,以及如何检测主存使用情况。 ...

    linux内存管理源代码导读

    Linux 内存管理源代码导读 Linux 内存管理是操作系统中最重要的组件之一,它负责管理计算机的内存资源,确保系统的正确运行。在 Linux 操作系统中,内存管理是通过页框管理、Slab 算法和动态存储器管理来实现的。 ...

    Linux内存管理详解.ppt

    Linux内存管理是操作系统的核心组成部分,尤其对于服务器和嵌入式设备等依赖稳定高效内存操作的环境至关重要。在Linux内核中,内存管理涉及到多个层面,包括分配、释放、碎片控制以及高速缓存优化等。 首先,Linux...

    Linux内存管理笔记

    Linux内存管理笔记详细介绍了Linux操作系统内核中内存管理机制的关键知识点,下面将依次对这些知识点进行详细说明: 存储器的层次结构:计算机系统采用分层的存储子系统以在存储容量、访问速度、成本效益之间取得...

    linux内存管理总结

    以下是Linux内存管理的一些关键知识点: 1. **内存管理工具**: - CodeViz:这是一个用于生成代码调用关系图的工具,可以帮助开发者理解代码间的调用结构,虽然在描述中没有详细展开,但它是分析Linux内核源码的...

    linux内存管理结构图

    Linux内存管理是操作系统的核心部分,它负责有效地分配和回收系统中的物理和虚拟内存。在Linux中,内存被划分为多个区域(Zone)和节点(Node),以优化内存的使用和性能。以下是对这些概念的详细解释: 1. **节点...

    Linux内存管理编程技术.doc

    Linux内存管理是操作系统的核心组成部分,它负责有效地分配、管理和回收内存资源。在Linux环境中,程序员通常通过系统调用和库函数来与内存管理接口交互。本实验主要关注两个方面:一是使用malloc()函数进行内存分配...

    Linux内存管理介绍

    ### Linux内存管理介绍 #### 虚拟内存与Linux 在深入探讨Linux内存管理之前,我们先了解一下虚拟内存的基本概念及其在Linux系统中的应用。虚拟内存是一种计算机内存管理技术,它通过将进程的虚拟地址空间映射到...

    一种Linux内存管理机制.pdf

    Linux内存管理机制包括多种层次和策略,旨在高效地分配和回收内存,避免内存耗尽和系统崩溃。本文将深入探讨Linux内存管理模型、伙伴系统、Slab分配流程以及内存回收策略。 首先,Linux内存管理模型将物理内存划分...

    linux内存管理

    ### Linux内存管理详解 #### 一、Intel x86保护模式下的分段与分页机制 在探讨Linux如何实现内存管理之前,我们首先需要理解Intel x86架构下的内存管理基础——分段与分页机制。 **分段机制**: - **段选择器**:...

    深入理解Linux内存管理

    ### 深入理解Linux内存管理 #### 一、引言与概述 本文档旨在深入探讨Linux 2.4版本中的内存管理系统。作者Mel Gorman在2004年撰写了这一篇详尽的文章,其内容涵盖了从启动时的内存分配到运行时内存管理的所有方面...

    Linux内存管理实验.pdf

    Linux内存管理实验是关于Linux操作系统内存管理机制的学习和实践。本实验中会涉及到诸多内存管理的关键概念和工具,如free、vmstat、readelf、objdump等。接下来将详细解释上述内容中涉及的关键知识点。 首先,free...

    linux内存管理工具

    linux内存管理工具

    Linux内存管理 vs. Windows 2000内存管理

    同时,Linux内存管理器提供不同类型的内存区域(如BSS、堆、栈等)以满足不同需求,并且有 slab 分配器优化小对象的分配和回收。 - **Windows 2000**:Windows 2000使用分代垃圾收集(Generational Garbage ...

    深入理解LINUX内存管理学习笔记

    我不可能完全理解LINUX内存管理的精髓,肯定有很多地方理解错误。希望大 家能够指正,以便提高,谢谢。 学习方法: 可能您第一次阅读的时候很多地方都不理解,不用担心。那您可能需要阅读一些 文件系统的知识。 或者...

    linux内存管理-物理内存管理.pdf

    整个内存管理系统可以分为2部分来看待: 第一部分是对物理内存的管理, 第二部分是对虚拟内存的管理. 物理内存管理的对象是板载的物理内存(DDRAM), 它把物理内存按页划分, 并把这些页放到一个池子里面. 物理内存管理...

    Linux内存管理编程

    Linux内存管理编程是操作系统核心部分的关键技术之一,它涉及到如何高效地分配、使用和回收内存资源。本实验旨在帮助你深入理解Linux环境下的内存管理机制,主要包括内存映射(mapping)和解除映射(unmapping),...

    Linux 内存管理详细介绍.docx

    "Linux 内存管理详细介绍" 本文将详细介绍 Linux 内存管理的概念、机制、重要性和组成部分,旨在帮助读者深入了解 Linux 内存管理的原理和实践。 一、Linux 内存管理概述 Linux 内存管理是指对系统内存的分配、...

    《深入理解LINUX内存管理》学习笔记c.PDF

    《深入理解LINUX内存管理》学习笔记c.PDF

Global site tag (gtag.js) - Google Analytics