网站建设初期目标,个人微信号做网站行吗,网站现状分析,软件开发工程师待遇怎么样文章目录 前言一、Linux进程空间内存分配二、malloc的实现机理三、物理内存与虚拟内存1.物理内存2.虚拟内存 四、磁盘和物理内存区别五、页页的基本概念#xff1a;分页管理的核心概念#xff1a;Linux 中分页的实现#xff1a;总结#xff1a; 六、伙伴算法伙伴算法的核心… 文章目录 前言一、Linux进程空间内存分配二、malloc的实现机理三、物理内存与虚拟内存1.物理内存2.虚拟内存 四、磁盘和物理内存区别五、页页的基本概念分页管理的核心概念Linux 中分页的实现总结 六、伙伴算法伙伴算法的核心概念伙伴算法的工作原理伙伴算法的优缺点优点缺点 伙伴算法的实现例子总结 前言
本篇文章开始讲解Linux的内存管理深入了解内存管理有助于我们深入Linux底层逻辑加强对Linux的学习和了解。
一、Linux进程空间内存分配
下面是一个32位的Linux进程空间内存排布具体的情况 内核空间1GB内核空间是操作系统核心代码和数据的所在区域。这部分空间由操作系统内核独占用于执行操作系统的任务如操作系统的调度、内存管理、驱动程序和系统调用等。在内核空间中所有的内核模块和驱动程序都运行并可以直接访问硬件资源。
用户空间3GB用户空间是给用户程序运行的区域其中包含了应用程序的代码、数据和堆栈等。用户空间是被操作系统管理和分配的用户程序在这个空间中运行并通过系统调用与内核进行交互。用户空间中的进程无法直接访问内核空间中的数据和功能而必须通过系统调用接口来请求内核的服务。
在用户空间中可以进一步细分不同的段
1.代码段存储可执行程序的指令即程序的二进制代码。
2.数据段存储全局变量和静态变量等数据。
3.堆区用于动态分配内存通过调用malloc()、new等函数实现。
4.栈区用于存储函数调用时的局部变量和函数调用的上下文。
这种地址空间的分配方式可以提供对操作系统和应用程序的良好隔离确保系统的稳定性和安全性。操作系统内核在内核空间中运行可以对硬件资源进行直接访问和管理而用户程序在用户空间中运行通过系统调用接口与内核进行通信实现各种操作和功能。
二、malloc的实现机理
当使用malloc函数时会调用到brk系统调用。
brk系统调用用于改变进程的数据段的结束地址从而调整进程的堆空间大小。当调用malloc函数时它会向操作系统请求一块指定大小的内存空间。操作系统会检查当前的堆空间大小并根据需要调整堆的结束地址以供新的内存分配。
malloc函数会调用brk系统调用来增加堆空间的大小以适应所需分配的内存大小。如果请求的内存大小超过了当前堆空间的剩余大小则操作系统会扩展堆空间使其满足请求。反之如果请求的内存大小较小当前剩余的堆空间可能会被重新分割并返回相应大小的内存块给malloc函数。
调用brk系统调用将会调用到下面的函数
这个函数的主要作用是根据用户空间的请求调整进程的数据段结束地址从而动态调整进程的堆空间大小。
SYSCALL_DEFINE1(brk, unsigned long, brk)
{unsigned long retval;unsigned long newbrk, oldbrk;struct mm_struct *mm current-mm;struct vm_area_struct *next;unsigned long min_brk;bool populate;if (down_write_killable(mm-mmap_sem))return -EINTR;#ifdef CONFIG_COMPAT_BRK/** CONFIG_COMPAT_BRK can still be overridden by setting* randomize_va_space to 2, which will still cause mm-start_brk* to be arbitrarily shifted*/if (current-brk_randomized)min_brk mm-start_brk;elsemin_brk mm-end_data;
#elsemin_brk mm-start_brk;
#endifif (brk min_brk)goto out;/** Check against rlimit here. If this check is done later after the test* of oldbrk with newbrk then it can escape the test and let the data* segment grow beyond its set limit the in case where the limit is* not page aligned -Ram Gupta*/if (check_data_rlimit(rlimit(RLIMIT_DATA), brk, mm-start_brk,mm-end_data, mm-start_data))goto out;newbrk PAGE_ALIGN(brk);oldbrk PAGE_ALIGN(mm-brk);if (oldbrk newbrk)goto set_brk;/* Always allow shrinking brk. */if (brk mm-brk) {if (!do_munmap(mm, newbrk, oldbrk-newbrk))goto set_brk;goto out;}/* Check against existing mmap mappings. */next find_vma(mm, oldbrk);if (next newbrk PAGE_SIZE vm_start_gap(next))goto out;/* Ok, looks good - let it rip. */if (do_brk(oldbrk, newbrk-oldbrk) 0)goto out;set_brk:mm-brk brk;populate newbrk oldbrk (mm-def_flags VM_LOCKED) ! 0;up_write(mm-mmap_sem);if (populate)mm_populate(oldbrk, newbrk - oldbrk);return brk;out:retval mm-brk;up_write(mm-mmap_sem);return retval;
}三、物理内存与虚拟内存
1.物理内存
物理内存是指计算机中实际存在的硬件内存。它是由RAMRandom Access Memory随机存取内存或其他类似的硬件组成的用于存储正在执行的程序和数据。物理内存是直接与计算机的中央处理器CPU相连提供快速、随机访问数据的能力。
2.虚拟内存
虚拟内存是操作系统提供的一种抽象概念。它扩展了可用的内存空间使得程序可以使用比物理内存更大的地址空间。虚拟内存将程序所需的内存分为连续的地址空间块称为虚拟地址空间。每个程序都有自己的虚拟地址空间这使得每个程序能够以独立的方式执行而不会互相干扰。
虚拟内存的工作原理是将部分程序和数据存储在物理内存中而将不常用的部分保存在磁盘上的交换文件中。当程序需要访问虚拟内存中的某个地址时操作系统会根据某种映射机制将虚拟地址转换为物理地址。这个过程被称为虚拟内存管理。通过这种方式系统可以运行更多的程序即使物理内存有限。
虚拟内存的主要优势之一是提供了更大的地址空间以支持大型程序和多任务操作系统。它还可以通过将不常用的数据存储在磁盘上来节省物理内存的使用并提供更好的内存管理和数据保护机制。
总结而言物理内存是计算机实际的硬件内存而虚拟内存是通过操作系统提供的抽象层面扩展的内存概念使得程序能够使用比物理内存更大的地址空间并提供更好的内存管理和保护机制。
四、磁盘和物理内存区别
物理内存和磁盘是不同的存储介质它们在计算机系统中扮演不同的角色和功能。物理内存用于临时存储当前正在执行的程序和数据而磁盘用于长期存储文件和持久性数据。
五、页
在 Linux 操作系统中“页”Page是内存管理中的一个重要概念尤其是在虚拟内存管理中。操作系统通过页来管理物理内存和虚拟内存之间的映射使得每个进程能够独立地使用其虚拟地址空间而不直接操作物理内存。这种分页管理有助于实现内存保护、内存共享、内存映射文件等机制。
页的基本概念 虚拟内存与物理内存 虚拟内存是操作系统为每个进程提供的虚拟地址空间。每个进程看到的内存地址是连续的这与实际的物理内存地址无关。物理内存是计算机硬件中的实际内存RAM其中存储了系统运行时的程序数据和操作系统的内核。 页的基本定义 页Page虚拟内存的基本单位操作系统将虚拟地址空间划分为大小相同的块每个块叫做“页”。通常一页的大小为 4KB也可以更大如 2MB 或 1GB具体大小取决于体系结构例如x86 体系结构通常为 4KB。页帧Page Frame物理内存的基本单位物理内存被划分为大小相同的块每个块叫做“页帧”对应虚拟内存中的“页”。 页表Page Table 页表是操作系统用于将虚拟地址转换为物理地址的结构。它存储了虚拟页到物理页帧的映射信息。每个进程都有自己的页表操作系统通过页表来实现虚拟内存到物理内存的映射。页表的结构通常是多级的如 2 级页表、4 级页表等以提高映射效率并减少内存消耗。
分页管理的核心概念 虚拟地址空间划分 虚拟内存被划分成多个大小相等的页。每个进程的虚拟内存都由操作系统划分成若干个虚拟页而每个虚拟页与物理内存中的页帧通过页表建立映射。 页面映射 在一个分页系统中每个虚拟地址空间的页都与物理内存的页帧相对应。操作系统使用页表来记录这种映射关系。 当进程访问虚拟内存时操作系统会通过查找页表来获取对应的物理内存地址。如果虚拟页没有映射到物理页帧即页面不在内存中操作系统会触发缺页异常Page Fault并将数据从磁盘加载到内存。 页替换 由于物理内存的有限性可能会发生内存不足的情况。这时操作系统需要将某些不常用的虚拟页面交换到磁盘上的交换空间Swap Space中将内存中的页面替换出来以腾出空间。当需要这些被替换的页面时它们会重新加载回内存。 大页Huge Pages 对于某些需要大量内存的应用程序如数据库、高性能计算等操作系统允许使用大页如 2MB 或 1GB 页以减少页表的开销。大页可以减少页表项的数量提高内存访问效率。 页对齐 在虚拟内存系统中页是按照一定的对齐方式来管理的通常是 4KB。页对齐确保了虚拟地址空间和物理内存的页边界一致性。 页面保护与权限 每个页都有一定的访问权限这些权限决定了该页面的访问行为 读权限Read写权限Write执行权限Execute 这些权限通过页表项设置并在进程访问该页面时由硬件控制。
Linux 中分页的实现
在 Linux 操作系统中虚拟内存管理采用了分页机制。具体来说Linux 中有以下几个关键组件与分页管理密切相关 内存管理单元MMU MMU 是硬件部分它负责执行虚拟地址到物理地址的转换。MMU 利用页表来进行地址转换确保虚拟内存和物理内存的隔离。 页表Page Table 在 Linux 中页表是用来维护虚拟地址到物理地址映射的结构。每个进程有自己的页表操作系统会维护内核的页表。页表结构通常是多级的包括顶级页表、二级页表等。 进程虚拟地址空间 每个进程拥有自己的虚拟地址空间Linux 会将进程的虚拟内存划分为多个区段如代码段、数据段、堆、栈等。每个区段的虚拟内存都有对应的页表条目。 缺页异常处理Page Fault Handling 当进程访问未映射的虚拟内存时MMU 会触发缺页异常。Linux 内核会处理缺页异常判断是通过磁盘交换加载数据还是分配新的物理页面来解决问题。 交换空间Swap Space 当物理内存不足时Linux 会使用交换空间swap将一些不常用的页存储到磁盘中从而腾出内存空间。交换空间的存在允许系统使用更多的内存尽管这会降低性能。
总结
页是内存管理的基本单位操作系统将虚拟内存分成多个大小相同的页并通过页表映射到物理内存的页帧。分页可以有效地隔离进程的虚拟内存提供内存保护、共享、以及懒加载等机制。Linux 使用分页机制来管理虚拟内存硬件的 MMU 和操作系统的页表配合工作来完成虚拟地址到物理地址的转换。
分页和虚拟内存技术使得操作系统能够更高效、安全地管理内存提高了系统的可伸缩性和稳定性。
六、伙伴算法
伙伴算法Buddy Allocation System是一种内存分配算法主要用于动态内存管理特别是在操作系统中用来管理物理内存的分配和释放。它通过将内存块分成具有2的幂大小的区域并通过将相邻的空闲块配对来实现高效的内存分配。
伙伴算法的核心概念 内存分配单位 伙伴算法将内存划分为大小为2的幂的块例如 2KB、4KB、8KB 等。每个内存块的大小是2的幂因此内存块的大小总是是 2, 4, 8, 16, 32, 64 … 等。 分区 内存被划分为多个固定大小的块例如 4KB、8KB、16KB这些块可以根据需要进行分配。当请求内存时算法会从大块开始寻找能够满足请求的内存块。 伙伴 内存中的每一块内存有一个“伙伴”这个伙伴是与该块内存相邻且大小相同的块。如果一个块的内存被分配另一个块它的伙伴会保持空闲状态直到其伙伴被释放。 合并与分裂 当一个内存块被请求时伙伴算法会根据请求的大小找到最小的、适合的空闲块。如果所需的内存块比当前空闲块大则需要分割一个更大的块并将其分成两个“伙伴”块。这个过程会一直递归下去直到找到合适的块为止。当释放内存时算法会检查是否有空闲块的伙伴如果有则将它们合并成一个更大的块。这个合并过程会递归进行直到没有更多的伙伴可以合并为止。
伙伴算法的工作原理 分配内存 当程序请求分配大小为 size 的内存时伙伴算法会在空闲内存块中寻找足够大的块。如果没有一个空闲块的大小与 size 精确匹配则从更大的块开始分配直到找到一个合适的块。对于大于请求的空闲块系统会将其分裂成两个相同大小的伙伴继续进行分配。 释放内存 当程序释放一个内存块时系统会检查它的伙伴是否也空闲。如果伙伴是空闲的两个伙伴块就会合并成一个更大的块。合并后的内存块会继续与它的伙伴合并直到没有更多的伙伴可以合并为止。合并过程是递归进行的可能会发生多次合并。
伙伴算法的优缺点
优点 快速分配和释放 由于内存块的大小是2的幂因此可以通过简单的计算快速找到合适的内存块。这使得内存分配和释放的速度比较快。 避免外部碎片 由于内存块大小的限制2的幂次即使内存中出现了一些“空闲”空间也能够通过合并操作将碎片整理成较大的块减少外部碎片问题。 内存合并 伙伴算法能够在释放内存时进行合并操作将相邻的空闲内存块合并成一个更大的内存块从而有效地利用了内存资源。
缺点 内部碎片 虽然伙伴算法可以避免外部碎片但由于内存块大小是2的幂次可能会出现内部碎片问题。即一个块比实际需要的内存大导致浪费一部分内存。例如如果请求的内存大小为 6KB但最小可分配的块为 8KB那么分配的内存将比实际需要的多出 2KB。 固定块大小 由于内存块的大小是2的幂次无法处理一些非常小的内存请求例如 1KB 或 3KB可能导致某些内存的浪费。 管理复杂度 伙伴算法的合并操作需要一定的管理工作尤其是在大量的内存块需要管理时。每次分配和释放内存时都需要更新伙伴关系。
伙伴算法的实现
在实现伙伴算法时通常使用一个位图Bitmap或者链表来管理每个内存块的空闲和占用状态。常见的实现方式如下 位图管理 使用一个位图来记录每个内存块的状态每个位表示一个内存块的状态空闲或已分配。对于每个内存块还会记录它的伙伴的位置。 链表管理 将每个大小相同的内存块放入一个链表中并通过合并操作将它们连接在一起。每个内存块都可以存储它的伙伴信息。 分配策略 当请求内存时算法会从最大的块开始查找直到找到能够满足请求的最小块。如果找到了更大的块则将它分割为两个相同大小的伙伴直到获得合适的块。 合并策略 在释放内存时算法会检查释放的块是否和它的伙伴是相邻的如果是相邻的并且空闲则将这两个块合并成一个更大的块并将新的块插入到链表中。
例子
假设内存的最小分配块为 16 字节并且内存总量为 64 字节。在内存管理开始时内存将被划分为多个 16 字节的块形成一个空闲块链表。假设用户请求了 24 字节的内存
由于请求是 24 字节而最小块是 16 字节伙伴算法将选择一个 32 字节的块进行分配。如果请求的内存已经分配出去系统会将剩余的 8 字节32 - 24与相邻的伙伴块进行合并形成一个 16 字节的块。
总结
伙伴算法是一个高效的内存分配和释放算法通过将内存块分成 2 的幂大小的块并通过合并相邻的空闲块来减少外部碎片。尽管它存在一定的内部碎片和管理复杂度但在许多操作系统和内存管理系统中它仍然是一种常用的内存分配策略。