VIRT 与 RSE 占用分析
1、概述
在Linux命令行中执行top命令,可以查询到所有进程使用的VIRT虚拟内存、RES常驻内存和共享内存SHR。那么,什么是VIRT虚拟内存、RES常驻内存和共享内存SHR?我们编写的Linux C++程序如何影响它们呢?
VIRT:
- 进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据,以及malloc、new分配的堆空间和分配的栈空间等;
- 假如进程新申请10MB的内存,但实际只使用了1MB,那么它会增长10MB,而不是实际的1MB使用量。
- VIRT = SWAP + RES
RES:
- 进程当前使用的内存大小,包括使用中的malloc、new分配的堆空间和分配的栈空间,但不包括swap out量;
- 包含其他进程的共享;
- 如果申请10MB的内存,实际使用1MB,它只增长1MB,与VIRT相反;
- 关于库占用内存的情况,它只统计加载的库文件所占内存大小。
- RES = CODE + DATA
SHR:
- 除了自身进程的共享内存,也包括其他进程的共享内存;
- 虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小;
- 计算某个进程所占的物理内存大小公式:RES – SHR;
- swap out后,它将会降下来。
2、程序验证
2.1 申请但未使用的堆空间不占用RES,但占用VIRT
1 |
|
top显示如下:
VIRT包含了new出来的512MB空间,但是RES不包含该空间。即malloc或new出来的空间,如果没有使用,会放入SWAP中,并不在内容中真实的分配物理内存。
2.2 申请且使用了的堆空间占用RES
1 |
|
top显示如下:
VIRT包含new出来的512MB空间,RES包含目前使用的memset的512M空间。即new出来的空间被使用后,会真实分配物理内存。
使用部分申请了的堆空间则RES显示使用的部分
1 |
|
top显示如下:
VIRT包含new出来的512MB空间,RES包含目前使用的memset的128M空间。即new出来的空间,如果只使用部分,则只分配部分物理内存。
2.3 申请但未使用的栈空间不占用RES,但占用VIRT
1 |
|
top显示如下:
没有使用的栈空间,VIRT会包含(没有使用的栈空间会在SWAP中)。
2.4 已经使用的栈空间,VIRT和RES都会包含
1 |
|
top显示如下:
2.5 局部申请的内存释放后RES并未减少
1 |
|
top显示如下:
在 currlwent i=1, p=0xfd0010
时RES开始增加,每次增加10M, 且一直占用,此问题主要由于Glibc的内存分配由brk和mmap两种内存内存分配策略导致。
从操作系统的角度看,进程的内存分配由两个系统调用完成:brk和mmap。brk是将数据段(.data)的最高地址指针_edata往高地址推,mmap是在进程的虚拟地址空间中找一块空闲的。其中,mmap分配的内存由munmap释放,内存释放时将立即归还操作系统;而brk分配的内存需要等到高地址内存释放以后才能释放,可通过在程序启动时增加以下代码,修改内存分配方式来解决问题
mallopt(M_MMAP_MAX, 0); // 禁止malloc调用mmap分配内存
mallopt(M_TRIM_THRESHOLD, 0); // 禁止内存缩进,sbrk申请的内存释放后不会归还给操作系统
修改后的代码如下:
1 |
|
经过以上的代码修改程序RES内存稳定再20MB
参考:
https://blog.csdn.net/huyiyang2010/article/details/7815491#
https://blog.csdn.net/hmylk/article/details/37761247
https://bbs.csdn.net/topics/330179712
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!