|
|
|
|
移动端

Linux内存的分配和释放是怎么回事儿?

当出现多个程序共同使用相同的文件映射(共享库)时,它们可以共享磁盘高速缓存中的同一空间,从而节省物理内存的使用量,这种技术就是”共享映射”技术。

作者:暗无天日来源:CU技术社区|2018-05-08 08:46

【新品产上线啦】51CTO播客,随时随地,碎片化学习

了解内存分配机制(共享映射与请求分页)

通过 pmap 命令,可以获取用户进程逻辑地址空间中映射的内存信息:

  1. pmap -x $pid 

其中 -x 表示获取详细信息。

下面是一个例子:

  1. pmap -x $(pidof emacs) |head -20 

其中,“Address(地址)”指的进程的逻辑地址空间。

“Kbytes”列表示的是对应逻辑地址的容量,以Kb为单位

“RSS”列表示的是实际使用的物理内存容量,由于分页机制的存在,这个值一般要比”Kbytes”的值要少。

“Mapping”列为逻辑内存的映射方式,其中”[annon]“表示通过malloc函数来分配的堆空间(匿名内存),”[stack]“为进程的栈空间,这两种映射都是将物理内存映射到进程的逻辑内存上去。 而”emacs-25.3″,”libpixbufloader-svg.so”等文件名则表示它们执行的是文件映射,他们对应的是磁盘上的文件。当这些文件被读入高速缓存后,相应的内存空间被映射成进程的逻辑内存。

当出现多个程序共同使用相同的文件映射(共享库)时,它们可以共享磁盘高速缓存中的同一空间,从而节省物理内存的使用量,这种技术就是”共享映射”技术。

除了共享库外,进程的fork也使用了共享映射技术。 当父进程fork子进程时,Linux内核并不对内存中的内容进行实际上的复制,而是将映射到父进程逻辑地址空间内的那部分内容原封不动地共享映射到子进程的逻辑地址空间内。 但为了防止父进程和子进程的内存操作相互影响,Linux内核在进行共享映射时,相应的内存区域会暂时设置为写保护。 当某一方进程试图操作内存时,会引发只读异常。内核检测到这个异常后,会复制操作的这个内存页,从而使两个进程都可进行独立写入。 这种在写入时复制的机制叫做“写时复制(copy-on-write)”

另一方面,进程将可执行文件或共享库文件内容读入内存并映射到进程逻辑地址空间上时,并不会读入全部的文件内容,而是先标记”该文件的内容已经被映射到逻辑地址空间内”. 当进程访问逻辑地址空间时,由于不存在对应的物理内存,会引发换页错误的异常。内容检测到该异常后会将所需部分以内存页为单位读入内存中。 这种只读入所需内容的机制,叫做请求分页。

了解内存释放机制

当其他进程需要新的物理内存时,就涉及到如何将尚有数据残余的物理内存释放或换出来的问题了。

当需要新物理内存时,会优先释放Inactive(file)和Active(file)中记录的内存页,只需要将脏数据写入文件中再释放内存页即可。

而Inactive(anon)和Active(anon)内存页则需要将内容交换到物理磁盘上的swap中后再释放。 具体来说,Linux会在进程页表上做一个标记,标记出换出内存所对应的逻辑地址。 当进程访问该逻辑地址时,会产生相应物理内存不存在的异常,Linux内核检测到这个异常后,会再次将数据从swap中加载入空闲内存,并重新配置页表信息。

Linux内核使用两种机制来加快换出处理速度:

  • 一种是预读。

当某一个内存页需要换入时,Linux内核会将其后的几个内存页一起换入。因为进程连续访问多个内存页的可能性很大。预读的页数为内核参数 vm.page-cluster 决定为 2^vm.page-cluster.

  • 另一种是交换缓存。

即在换入某个内存页后,物理磁盘上交换空间中仍然保留原数据,这种状态的内存会记录在“交换缓存”的列表上。这样当需要再次换出记录在“交换缓存”上的内存页的数据时,就无需再次换入了。

每个进程的内存使用情况可以通过查看 /proc/进程ID/status 来查看

  1. cat /proc/$(pidof emacs)/status 
  1. Name: emacs 
  2. Umask:  0022 
  3. State:  S (sleeping) 
  4. Tgid: 6769 
  5. Ngid: 0 
  6. Pid:  6769 
  7. PPid: 1 
  8. TracerPid:  0 
  9. Uid:  1000  1000  1000  1000 
  10. Gid:  1000  1000  1000  1000 
  11. FDSize: 64 
  12. Groups: 986 998 1000 
  13. NStgid: 6769 
  14. NSpid:  6769 
  15. NSpgid: 6769 
  16. NSsid:  6769 
  17. VmPeak:   567040 kB 
  18. VmSize:   567040 kB 
  19. VmLck:         0 kB 
  20. VmPin:         0 kB 
  21. VmHWM:    241176 kB 
  22. VmRSS:    241176 kB 
  23. RssAnon:    204544 kB 
  24. RssFile:     36604 kB 
  25. RssShmem:       28 kB 
  26. VmData:   231712 kB 
  27. VmStk:      1596 kB 
  28. VmExe:      2332 kB 
  29. VmLib:     47832 kB 
  30. VmPTE:      1008 kB 
  31. VmSwap:        0 kB 
  32. HugetlbPages:        0 kB 
  33. CoreDumping:  0 
  34. Threads:  4 
  35. SigQ: 1/15456 
  36. SigPnd: 0000000000000000 
  37. ShdPnd: 0000000000000000 
  38. SigBlk: 0000000000000000 
  39. SigIgn: 0000000004381000 
  40. SigCgt: 00000001db816eff 
  41. CapInh: 0000000000000000 
  42. CapPrm: 0000000000000000 
  43. CapEff: 0000000000000000 
  44. CapBnd: 0000003fffffffff 
  45. CapAmb: 0000000000000000 
  46. NoNewPrivs: 0 
  47. Seccomp:  0 
  48. Cpus_allowed: 3 
  49. Cpus_allowed_list:  0-1 
  50. Mems_allowed: 1 
  51. Mems_allowed_list:  0 
  52. voluntary_ctxt_switches:  12951 
  53. nonvoluntary_ctxt_switches: 21641 

其中比较有用的项有:

VmData

data段的大小

VmExe

text段的大小

VmHWM

当前物理内存使用量的最大值

WmLck

用mlock锁定的内存大小

VmLib

共享库的使用量

VmPTE

页面表的大小

VmPeak

当前物理内存的最大值

VmRSS

物理内存的实际使用量

VmSize

逻辑地址的大小

VmStk

堆栈的大小

VmSwap

交换空间的使用量

【编辑推荐】

  1. 这里帮你总结了一下Linux下查看内存使用情况的多种方法~
  2. Linux ARM的存储分布那些事
  3. Spark streaming中持久保存的RDD/有状态的内存
  4. Linux存储入门:简易数据恢复方案--分区和LVM实战
  5. Accordion :一种HBase内存压缩算法
【责任编辑:武晓燕 TEL:(010)68476606】


点赞 0
分享:
大家都在看
猜你喜欢

热门职位+更多

读 书 +更多

黑客入侵的主动防御

本书是一本非常全面地讲述黑客入侵主动防御技术的网络安全工具书。本书的重点是介绍黑客的攻击手段和提供相应的主动防御保护措施,在组织结...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊