为什么第二次calloc不分配物理内存?

zcphoenix 2018-11-30 10:16:01
最近观察正在开发的服务的内存使用情况,发现了'calloc'函数一些有趣的现象:
第一次调用'calloc'会正常分配物理内存;
第二次调用'calloc'则不会分配物理内存——准确地说,第二次'calloc'的内存不写入则不会分配物理内存,写入时则是写入多大内容则分配多少物理内存。

具体代码在后面,执行结果如截图:
1). 下面代码执行结果,从top命令看虚存分配了2G,但只分配了1G的物理内存,


2). 放开注释掉的代码,从top命令看虚存分配了2G,但只分配了1.5G的物理内存。


哪位大神帮忙解答一下,这是怎么一个情况?编译器做了优化么?还是系统行为?多谢多谢~~


#include <stdlib.h>
#include <stdio.h>

int main() {
struct timeval start, end;
size_t K = 1024;
size_t M = K * K;
size_t G = M * K;
size_t size = G;

printf("first calloc ...\n");
void *p1 = calloc(1, size);

printf("second calloc ...\n");
void *p2 = calloc(1, size);
/*
long long i = 0;
for (i = 0; i < size / 2; i++) {
if (0 != *((char*)(p2) + i)) {
printf("non-zero: p2[%d] = %d\n", i, *((char*)(p2) + i));
} else {
*((char *)(p2) + i) = i;
}
}
*/

getchar();

printf("free.......\n");
free(p1);
free(p2);

return 0;
}


...全文
312 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2018-12-03
  • 打赏
  • 举报
回复
Linux不是开源的吗?
zcphoenix 2018-12-03
  • 打赏
  • 举报
回复
引用 5 楼 amei113 的回复:
Linux 下 calloc 分配内存时,并没有分配实际物理内存,只是分配了虚拟内存,这些虚拟内存在页表中对应同一个物理地址,且标记为只读。当读calloc分配的地址时,读到的是同一个物理地址,当写calloc的分配的地址时,发生page fault,然后重新映射一个物理地址,这个时候才真正分了物理地址。这段代码两个calloc分配的地址,都没写操作,按理物理内存是基本没用到,但你说第一次分配占用了1g物理内存,我觉得还要再实验确定一下


从top命令看是这样的~~
zcphoenix 2018-12-03
  • 打赏
  • 举报
回复
引用 4 楼 死国之神 的回复:
一次申请1G的连续空间,是一件比较困难的事情,判断一下返回值,为NULL 则是操作系统没有批准你的申请,故而没有给你分配内存。


Windows和Linux分别加了指针判断,两次calloc的内存都不做任何访问,结果如下:

Windows下,根据任务管理器,两次calloc都不会分配物理内存,两次calloc貌似都会根据实际内存是否足够决定返回结果:
我机器内存是12G的,两次calloc分配8G的空间的话,显示都返回非空指针;两次9G,则第一次成功、第二次失败;两次10G,则都失败。。。
Linux下测试,根据top命令结果,第一次calloc如果实际内存足够,则分配物理内存,否则分配失败返回空指针;第二次calloc不分配物理内存,但是会根据实际内存是否足够,返回非空指针或空指针。
water-moon 2018-12-01
  • 打赏
  • 举报
回复
Linux 下 calloc 分配内存时,并没有分配实际物理内存,只是分配了虚拟内存,这些虚拟内存在页表中对应同一个物理地址,且标记为只读。当读calloc分配的地址时,读到的是同一个物理地址,当写calloc的分配的地址时,发生page fault,然后重新映射一个物理地址,这个时候才真正分了物理地址。这段代码两个calloc分配的地址,都没写操作,按理物理内存是基本没用到,但你说第一次分配占用了1g物理内存,我觉得还要再实验确定一下
云山大侠 2018-11-30
  • 打赏
  • 举报
回复
Linux 不是一个保守的操作系统,你申请了多少内存,并不意味着你会用到多少内存,所以系统也不会立即给你分配多少内存,而且当所有程序申请的内存超过最大物理内存和swap的总和后,Linux还是会允许别的程序申请内存,所以Linux能够用最少的资源干最多的事情,这也是Linux设计的初衷。
Windows是一个保守的操作系统,你申请了多少内存,不管你用不用得到,系统都会立即给你分配,且当所有内存已经到达最大物理内存和虚拟内存总和后,Windows不会再允许别的程序申请内存。
云山大侠 2018-11-30
  • 打赏
  • 举报
回复
一次申请1G的连续空间,是一件比较困难的事情,判断一下返回值,为NULL 则是操作系统没有批准你的申请,故而没有给你分配内存。
云山大侠 2018-11-30
  • 打赏
  • 举报
回复
引用 2 楼 zcphoenix 的回复:
[quote=引用 1 楼 死国之神 的回复:]
Linux 不是一个保守的操作系统,你申请了多少内存,并不意味着你会用到多少内存,所以系统也不会立即给你分配多少内存,而且当所有程序申请的内存超过最大物理内存和swap的总和后,Linux还是会允许别的程序申请内存,所以Linux能够用最少的资源干最多的事情,这也是Linux设计的初衷。
Windows是一个保守的操作系统,你申请了多少内存,不管你用不用得到,系统都会立即给你分配,且当所有内存已经到达最大物理内存和虚拟内存总和后,Windows不会再允许别的程序申请内存。


我在Windows下做了同样的测试,和Linux结果确实不一样,但是Windows不是立即分配物理内存,而是连续两次“calloc”都不分配物理内存~~
此外,还有一个不同点是,Linux对于“calloc”的内存进行读操作时,依然不分配物理内存;但是Windows在对“calloc”的内存进行读操作时,则分配物理内存了,而且是“按需分配”~~[/quote]
判断一下返回值
zcphoenix 2018-11-30
  • 打赏
  • 举报
回复
引用 1 楼 死国之神 的回复:
Linux 不是一个保守的操作系统,你申请了多少内存,并不意味着你会用到多少内存,所以系统也不会立即给你分配多少内存,而且当所有程序申请的内存超过最大物理内存和swap的总和后,Linux还是会允许别的程序申请内存,所以Linux能够用最少的资源干最多的事情,这也是Linux设计的初衷。
Windows是一个保守的操作系统,你申请了多少内存,不管你用不用得到,系统都会立即给你分配,且当所有内存已经到达最大物理内存和虚拟内存总和后,Windows不会再允许别的程序申请内存。


我在Windows下做了同样的测试,和Linux结果确实不一样,但是Windows不是立即分配物理内存,而是连续两次“calloc”都不分配物理内存~~
此外,还有一个不同点是,Linux对于“calloc”的内存进行读操作时,依然不分配物理内存;但是Windows在对“calloc”的内存进行读操作时,则分配物理内存了,而且是“按需分配”~~

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧