Linux内存[翻译]

来源:互联网 发布:电脑风扇反转软件 编辑:程序博客网 时间:2024/05/16 14:52

参考资料

Linux Agent 采集项说明 - 内存
Memory – Part 1: Memory Types
Memory – Part 2: Understanding Process memory

ipcs深入分析

虚拟内存

现代操作系统中, 每一个进程都都存活在各自的内存空间内. 但是操作系统并没有直接把内存地址对应硬件地址, 而是提供了一个硬件抽象层, 而为每一个进程创造了虚拟内存. 物理内存和虚拟内存之间的映射关系, 是由CPU 使用一个映射表转换得到的, 这个表由内核维护, 每一个进程在表中有一条记录.
虚拟内存有多个目的. 第一, 允许进程隔离. 一个进程只能够与虚拟内存中内存沟通. 这样它只能存取自己这个进程所关联的数据, 不能看到其他进程的内存数据. 第二, 硬件抽象. 内核可以自由的更改物理内存地址和虚拟内存的映射关系. 它也可以选择不给虚拟内存提供任何真实的物理内存, 除非真的需要. 而且它可以在虚拟内存长时间未使用, 而且物理内存吃紧的时候交换到硬盘上. 总的来说, 虚拟内存的存在使得内核更加自由, 唯一的限制是, 当程序需要读取内存的时候需要换算出原本数据写在哪儿. 第三, 它可以把不在RAM 中的存储单位当做内存. 这是mmap 和映射文件的原理. 可以把一个文件当做一段内存, 这样存取这个文件就像一段内存缓冲区. 这使得写代码比较简洁. 第四, 为了共享. 既然内核知道有哪些进程已经映射到虚拟内存中了, 就可以避免重复加载数据到内存, 而是重复利用指向物理内存的虚拟地址. 共享的结果就是内核使用COW (copy on write): 当两个进程使用同一份数据, 但是当其中一个更改了数据, 另一个进程不允许看到改变, 内核就会复制一份改变前的数据(类似Oracle 数据库的多版本机制).

fork()

最著名的COW 的案例就是fork(). 在类Unix 系统中, fork() 是一项系统调用, 可以复制现有的进程再造一个. 当fork() 返回时, 两个进程将处于相同的进度(打开的文件, 内存等等 相同). 由于COW 机制, fork() 并没有真的复制了一份进程的内存, 只有父进程改变的数据才在RAM 中复制. 由于大多数使用fork() 的场景中都立刻调用了exec(), 是的整个虚拟内存空间作废, COW 机制避免了父进程复制的内存完全无用.
另一个副作用是, fork() 用很低的成本创造了进程的私有内存的快照(snapshot). 如果你想在进程的内存中做一些操作, 但又害怕改坏了什么, 又不想去debug, 尽管fork()

Pages 分页

虚拟内存被拆分为Pages. 分页的大小由CPU 规定, 通常为4KiB. 这意味着内核中管理内存的粒度是4K. 当请求内存的时候, 内核返回的将是1 个或多个Pages, 当释放内存的时候也是以Page 为单位(Oracle 默认数据文件格式8K), 任何封装良好的API, 例如malloc, 都是在用户端发起的.
对每一个分配的Page, 内核保持了一组特权(permission): Page 可以被读, 写, 或者执行. 这些特权在分配内存的时候, 或者在之后调用mprotect() 的时候被设置. 没有被分配的Page 不能被存取.

内存类型

不是所有在虚拟内存中分配的内存都是一样的. 我们可以从两个方向分类. 第一类是内存是否是私有的或者共享的. 第二类是内存是否是file-backed. 这创造了一个4 个内存种类的分类.
private shared
anonymous
1. stack mmap(ANON, SHARED)
2. malloc()
3. mmap(ANON, PRIVATE)
4. brk()/sbrk()
file-backed 1. mmap(fd, PRIVATE) mmap(fd, SHARED)
2. binary/shared libraries

Private Memory

私有内存是进程独有的. 大多数程序使用的都是私有内存.
由于私有内存不能被其他进程存取, 所以私有内存服从COW. 副作用是, 即使内存是私有的, 多个进程也会共享一段物理内存去存储数据. 例如二进制文件和shared libraries.

Shared Memory

共享内存是设计用来实现进程间的通信. 当共享内存被修改, 其他进程可以看到改变.

Ananymous Memory

匿名内存全部在RAM 中. 但是内核不会在真正在RAM 写入之前分配地址.

File-backed and Swap

如果内存映射是file-backed, 数据是从磁盘上加载. 多数时候, 用的时候才加载. 但也可以控制内核提前加载. 物理内存不够用的时候, 内核会从RAM 移动一些数据到磁盘. linux 中, swap 是磁盘上一个特殊区域. 由于虚拟内存, swap pages 对进程来说完全是透明的.


去年来腾讯之后, 一直忙的云里雾里, 都没有空自己学点东西, 更别说写博客了. 当时在公司内网看到这个系列的linux 内存的文章, 粗枝大叶的翻译了第一二篇, 然后放在这里生尘灰, 半年都没有管他. 今天好不容易闲下来, 打开博客一看, 竟然有两千的阅读量, 真是意外啊. 所以我决定要重新润色一下这个系列的文章, 把没有完成的部分接着翻译下去, 才对得起看客们不小心点进来的时间啊!

0 0