=Start=
缘由:
周末闲来无事,深入学习、整理一下malloc/calloc的知识
正文:
参考解答:
Why does malloc initialize the values to 0 in gcc?
简而言之:
没有,只不过在你的例子中它恰好是零。
并且,你的测试用例并没有显示(所有的)数据都为0。它只显示了一个元素是否为0。
复杂一些的解释:
当你调用malloc()时,有两件事会发生:
- 它从同一个进程之前分配和释放的内存中进行回收后再分配;
- 它向操作系统申请新的内存页;
在第一种情况下,申请的内存中将包含以前分配中剩余的数据。所以它不会是零。这是执行小块内存分配时的常见情形。
在第二种情况下,申请的内存来自于操作系统。当程序耗尽内存时,或者当你请求一个非常大块内存的分配时,就会发生这种情况。(在你的例子中也是如此)
这里就有一个问题:出于安全考虑,来自操作系统的内存将被归零。
当操作系统给你分配内存时,内存可能是从不同的进程中释放出来的。因此,内存在可能会包含敏感信息,比如密码。为了防止你读取这些数据,操作系统会在它给你之前将它归零。
*我注意到,C标准在并没有说明这一点。这是严格的操作系统行为。因此,这个归零操作可能不存在于安全不受关注的系统中。
为了提供更多和性能相关的背景知识:
正如 @R. 在评论中提到的,这个归零操作就是为什么你应该总是使用calloc()而不是malloc()+memset()组合。因为calloc()可以利用这个事实来避免单独的memset()。
不过另一方面,这种归零操作有时会是性能瓶颈。在一些数值应用程序中(比如不存在的FFT),你需要分配大量的scratch内存。使用它执行任何算法,然后释放它。
在这些情况下,归零操作是不必要的,并且是纯粹的开销。
我所见过的最极端的例子是,在70秒的操作中花费了20秒的时间对48 GB的缓冲区进行归零操作。(大约30%的开销)(当然,这台机器确实缺少内存带宽。)
最明显的解决方案是简单地手动重用内存。但这通常需要打破已经建立的接口。(特别是如果它是库例程的一部分)
malloc() allocates size bytes and returns a pointer to the allocated memory.
The memory is not cleared. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
Difference between malloc and calloc?(malloc和calloc的不同之处)
// void *malloc(size_t size); ptr = (char **) malloc (MAXELEMS * sizeof(char *)); // void *calloc(size_t nmemb, size_t size); ptr = (char **) calloc (MAXELEMS, sizeof(char*));
calloc()会用零初始化缓冲区,而malloc()则未将内存初始化。
归零操作可能需要花费一些时间,因此如果性能是一个问题,那么你可能需要使用malloc()。如果初始化内存更重要,请使用calloc()。比如,用了calloc()你就不需要在malloc()之外再调用memset()。
Does malloc lazily create the backing pages for an allocation on Linux (and other platforms)?
Linux确实延迟了页面(内存)分配,也就是「乐观的内存分配」。从malloc返回的内存没有任何东西支持,当你使用它时,你可能会碰到一个OOM状况(如果你请求的页面没有交换空间),在这种情况下,进程会被随意终止。
可以去 http://www.linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html 看实际例子。
什么时候该使用malloc?(When to use malloc for char pointers)
当你需要 创建/格式化 一个新字符串时,就应该使用malloc(然后要记得free);如果只是简单的指向一个字符串,并不需要用malloc在字符串指针上。
是否有必要在malloc()之后显示调用memset()对申请的内存进行初始化操作?(Do I have to memset after malloc new memory?)
malloc不会对由它分配的内存进行初始化操作。所以,你得到的内容里面的数据是随机的。如果你真的需要将一切设置为0,那么就使用在性能上有一定损耗的calloc来实现。(如果你需要初始化为非0的内容,那么可以使用memset对字节数组进行初始化,其它类型的就需要手动对数组进行循环来初始化它。)
对内存进行归零操作(zeroing out memory)
// first choice char buffer[1024] = {0}; // second choice char buffer[1024]; memset(buffer, 0, sizeof(buffer)); // second.2 choice char *buffer; buffer = malloc(sizeof(char) * 1024 ); if( buffer == NULL ) { /* Error management */ } memset(buffer, 0, sizeof(char)*1024 ); // third choice char *buffer; buffer = calloc(sizeof(char), 1024 ); if( buffer == NULL ) { /* Error management */ }
参考链接:
- 如上
=END=
《 “malloc的知识点学习” 》 有 6 条评论
malloc 背后的系统知识
http://legendtkl.com/2017/03/21/malloc-os-knowledge/
写扩展性好的代码:函数
http://legendtkl.com/2016/11/05/code-scalability/
动态内存管理
http://ialloc.org/posts/2013/07/15/memory-allocator-notes/
我们应该检查malloc的返回值么?
http://idning.github.io/should-we-check-malloc.html
http://stackoverflow.com/questions/1941323/always-check-malloced-memory
`
nginx 和 mysql, redis 做的差不多,尽量检查。
推荐的做法:
alloc里面如果有NULL就打日志,上层每次检查,发现NULL处理错误
对小的alloc, alloc 后写ASSERT
`
http://man7.org/linux/man-pages/man3/calloc.3.html
Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解
http://www.cnblogs.com/phpgo/p/5794342.html
`
calloc()函数的第二个参数是「每个元素的大小」,并非初始化时填充的内容!calloc()函数得到的内存空间是经过初始化的,其内容全为0。
calloc()函数有两个参数,分别为元素的个数和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小。
`
【Kernel】内存管理
http://blog.csdn.net/iEearth/article/details/79350927
LWN:尽快释放被杀死的进程内存
https://mp.weixin.qq.com/s/9sHPMAOKGIvQt8k9KSEJYw
https://lwn.net/Articles/785709/