malloc申请内存一定会引起进程的Rss变化吗?

前言

linux的开发人员,大概都知道可以通过 cat /proc/pid/smaps 来查看进程的memory占用情况,以确定线程占用memory是否过大:

malloc申请内存一定会引起进程的Rss变化吗?

可以看到每个大的字段都有size、Rss、Pss等不同的小的字段,它们可以各自理解为:

size:该字段所占用的虚拟内存大小

Rss/Pss:该字段所占用的物理内存大小;两者的区别在于,举例来说,libc-2.17.so被进程A和进程B都加载了,但实际上,这种共享的so所占用的物理内存是一份,而不是占用2份,那么假设libc-2.17.so的size为10KB,并且有且只有进程A和B加载这个so,那么进程A和B中的 libc-2.17.so 字段的Rss就是10KB,而Pss就是5KB,就是Rss是单独计算每一份所占用的内存,哪怕这一份是共享的;而Pss会更合理一些,会除以加载这一份的进程的数目;还有一个Uss,就不说了。

问题

当前我的工作就是把用户层面的虚拟内存和物理内存给对应起来,在验证已完成的方案时,发现一个问题,或者说不止一个问题。

测试1:
while(1)
{
 printf("xxxx");
 sleep(1);
}
测试结果:该线程的smaps信息里没有heap段
是否符合预期:是

测试2:
num = 0;
while(1)
{
 if(0 == num)
 {
  void* buff = (void*)malloc(1024*1024*10);
  *((int*)buff) = 1;
 }
 else
 {
  printf("XXXXX");
 }
 sleep(1);
 num++;
}
测试结果:该线程的smaps信息里没有heap段
是否符合预期:不符合预期,应该有heap字段

测试3:
num = 0;
while(1)
{
 void* buff = (void*)malloc(1024);
 if(0 == num)
 {
  *((int*)buff) = 1;
 }
 else
 {
  printf("XXXXX");
 }
 sleep(1);
 num++;
}
测试结果:

该线程的smaps信息里有heap段,但是heap里的RSS的值不断增大;并且通过自己的测试代码可以把申请的每个buff(虚拟地址)都对应到物理页面上
是否符合预期:

不符合预期,heap里的RSS应该维持不变;应该没有物理页面对应

 

下面一个一个来说:

测试2中,malloc申请了内存,但smaps里为啥没有呢?

在这里,首先上一张图,比较经典,但很多人看到了可能也没思考其中的细节:

malloc申请内存一定会引起进程的Rss变化吗?

声明:上面的图不是原创,侵权的话请通知我来删除

注意上面里的2个不同的字段:Heap、Memory Mapping Segment

其中,Heap就是咱们平时所说的堆内存了,也是我之前所理解的malloc 所对应的——后面的理解是错的

在这里感谢微信认识的大神朱志远,感谢他的指导和帮助!

直接说结果吧,定位过程不复杂,通过strace跟踪一下进程的系统调用就可以看到,malloc对应的系统调用时mmap,不是brk!

而mmap申请的内存对应的是Memory Mapping Segment,brk申请的内存对应的才是Heap段;

malloc申请内存一定会引起进程的Rss变化吗?

 

第二个问题,测试3里malloc申请的内存,如果没有被改写,那么是不会分配物理内存的,也就是进程的RSS实际上是不会增加的——但实际上是一直不停的增加!

经过多轮不同的测试,也没有发现什么问题,后来突然之前看到的关于malloc源码剖析的文章,里面提到malloc申请buff(大小为size)时,实际上是申请了sizeof(header) + size 大小的buff,然后把前面的header偏移过去,返回给用户的是size大小所对应的;前面的header里存放了buffer的size和下一个空闲的buff等信息,也就是说,header所对应的buff是会被改写的,这就会引发缺页中断,而被分配物理页面,所以Rss的size会不断增加;

后面写了另外的测试代码来验证这个想法,测试结果符合预期;

 

结论

1.malloc下面可能会调用brk,也可能会调用mmap;其中,brk所对应的是heap,而mmap对应的是Memory Mapping Segment;这两者在进程的smaps信息里也不是不同的:heap对应的就是heap,但是Memory Mapping Segment 对应的是没有字段说明的;

2.malloc申请的内存会涉及到header信息的填充,可能会引起缺页中断(注意是可能,不是一定),导致smaps信息里统计到的Rss值的增加;