用 c 分配内存,为什么普遍都是用 malloc 而不是用 calloc ? calloc 会初始化为 0,更安全啊?《深入理解 c 指针》里,我记得也是 malloc 用的多。百度了一下,没看到比较好的解释。我是用 calloc。
1
junkun 2019-06-10 21:41:55 +08:00 2
实际应用中可能申请之后,就直接赋值或初始化了,或者今后会初始化(比如申请内存做栈,没使用的部分就未初始化)。calloc 直接赋值为 0,很可能是不必要的,尤其在申请空间较大的情况下,尤其是一些老的编译器可能不会做这样的优化。
|
2
zhuangzhuang1988 2019-06-10 22:01:45 +08:00
实际上你看开源的库都是有个自己 Memory 包装的
里面想怎么玩怎么玩 |
3
zmj1316 2019-06-10 22:13:04 +08:00 via Android
性能 填 0 也没什么意义
vs 里面 debug 下默认就是填 0xcc 更不容易搞错 |
4
pkookp8 2019-06-10 23:11:51 +08:00 via Android 1
我觉得大家学习的时候第一个接受到的是 malloc,并且被教导使用未初始化的内存是很危险的,这个可能也是一个原因,所以大家常用 malloc
malloc 是 memory alloction,也比较好记 平时看到代码中也有 malloc+memset 的写法,应该是写的人不知道 calloc 的功能 其实现代编译器和芯片不会真的因为 malloc+memset 改成 calloc 性能就上升一大截,如果是的话还是从考虑优化代码角度考虑 |
5
msg7086 2019-06-11 01:45:21 +08:00 via Android
甚至 memset 可以用优化过速度更快的版本。
|
6
kingcos 2019-06-11 01:54:10 +08:00 via iPhone
有同样的疑问。
|
7
autogen 2019-06-11 02:01:57 +08:00
所以才会有红红火火恍恍惚惚烫烫烫烫烫。。。。
|
8
wheeler 2019-06-11 08:01:43 +08:00 1
个人觉得主要是 0 字节作为的初始化的场景不是那么多。比如 NULL 指针,浮点数 0.0,C 标准都没有规定它们的底层表示是 0 字节。
https://stackoverflow.com/questions/1538420/difference-between-malloc-and-calloc malloc 比 calloc 快也不一定对,这与实现有关系。 void *malloc(size_t size); void *calloc(size_t nmemb, size_t size); calloc 相对于 malloc 可能的一点好处是: calloc 的函数原型是 nmem + member_size 的形式,而如果用 malloc 的话得: malloc(nmem * member_size); 这时得考虑无符号乘法溢出的问题了,用 calloc 的话也不是一点问题没有,还是得看实现。见: https://wiki.sei.cmu.edu/confluence/display/c/MEM07-C.+Ensure+that+the+arguments+to+calloc%28%29%2C+when+multiplied%2C+do+not+wrap |
9
0x11901 2019-06-11 08:21:15 +08:00
书上和老师这么教的。
|
11
pwrliang 2019-06-11 08:30:40 +08:00
我认为大多场景都是申请空间,然后灌满,再读取多次。主动填 0,会不会在大多数场景都影响性能?
|
12
urmyfaith 2019-06-11 08:55:57 +08:00
在需要填 0 的时候,就是用 calloc;
在不关系初始值,或者明确会覆盖的话,直接 malloc 不是更省操作. |
13
urmyfaith 2019-06-11 08:57:31 +08:00
另外,很多人可能不知道有 calloc 这个东西.
导致 malloc + memset 或者 malloc + bzero 之类的. |
14
xdeng 2019-06-11 09:22:21 +08:00
当你明确知道要用多大空间覆盖多少内容的时候,申请时去填 0 简直是多此一举。
|
15
zycpp 2019-06-11 10:23:49 +08:00 via iPhone
C 语言的大原则是程序员知道自己在干什么,
在这个前提下,也就没必要初始化了, |
16
junkman 2019-06-11 10:32:20 +08:00 2
@wheeler 赞同
实际上,calloc 的实现在多数操作系统的实现和 malloc 几乎一样快,比如 Linux/FreeBSD 内核可能会直接返回 pre zero-mapped pages。 > You're likely to still see a performance improvement without overcommit. The OS will try to zero free pages in the background, so there's a good chance that it'll have pre-zeroed pages to hand you when you ask for them, rather than making you wait for them to be zeroed on demand. Of course, there are plenty of systems where this doesn't happen, or there are no pages in the first place, or there's no kernel zeroing stuff for you. 回到问题本身,我觉得这个可能是历史原因,早期 calloc 作为一个库函数用于消除平台之间内存分配的差异,当初实现初始化零也是直接按字节填零操作的,可能是出于防御性编程的考虑(当时可能还没有这种概念),方便 debug。可能和 @wheeler 所说的类似,零内存使用场景并不大,而且清零还费时(当时机器性能可不如现在这么强大),malloc 孕育而生。大部分情况下申请内存之后我们都会填入一些数据,这样来看,使用 malloc 可以获得 performance agin。 > So the (slightly modified) question still stands: Why do calloc and malloc exist? Indeed it looks like calloc was originally intended as a portable way to allocate memory. It used the function alloc which apparently was not meant to be used directly; most iolib functions have a 'c' tacked on. So when iolib was reworked into the stdlib why was calloc kept? saretired suspects backward compatibility but I don't believe this, because no other c-prefixed iolib function was kept and i couldn't find any code that actually used calloc in the v6 distribution either. So maybe whoever is responsible for malloc/calloc in v7 (I think it was ken, not dmr) thought malloc should be a public function but saw a use for calloc and changed the semantics to be a bit more predictable. see: https://news.ycombinator.com/item?id=13108434 如果什么地方说的不对,麻烦指正。:-P |
17
junkman 2019-06-11 10:33:28 +08:00
performance agin -> performance gain
|
18
xuddk727 2019-06-11 10:42:58 +08:00
做下位机开发的不知道什么情况,我只知道桌面开发一般都会有自己的内存分配策略,因为一些情况下可能得根据分页情况做性能优化,另一种是使用内存池,所以很少见,当然不是没有人用,不然何来屯屯屯屯屯屯和烫烫烫烫烫烫
|
19
africwildman OP 听了大家讨论,很受教啊。
|
20
wutiantong 2019-06-11 11:21:52 +08:00
@wheeler 感谢分享
|
21
Yggdroot 2019-06-11 14:53:43 +08:00
先问是不是,再问为什么。难道不是 prefer calloc to malloc?
|
22
tigereatsheep 2019-06-13 20:04:26 +08:00
如果让我来实现编译器
在 32 位的机器上 void *malloc(size_t size) 函数可以简单地把 SP 寄存器中的值加了 size * 4, 而 void *calloc(size_t nmemb, size_t size) 函数还需要把原 SP~SP+size * 4 地址中的内存值都初始化一下, 那么 malloc 会快一些,但是一些细心的码农在做编译器的时候可能还会做一些保护之类的事,这样效率就不好说了 |
23
tigereatsheep 2019-06-13 20:08:09 +08:00
说错了,应该是 FP 寄存器。。。
|