首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  C/C++/Obj-C

用 c 分配内存,为什么普遍都是用 malloc 而不是用 calloc?

  •  
  •   africwildman · 40 天前 · 3038 次点击
    这是一个创建于 40 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用 c 分配内存,为什么普遍都是用 malloc 而不是用 calloc ? calloc 会初始化为 0,更安全啊?《深入理解 c 指针》里,我记得也是 malloc 用的多。百度了一下,没看到比较好的解释。我是用 calloc。

    23 回复  |  直到 2019-06-13 20:08:09 +08:00
        1
    junkun   40 天前   ♥ 2
    实际应用中可能申请之后,就直接赋值或初始化了,或者今后会初始化(比如申请内存做栈,没使用的部分就未初始化)。calloc 直接赋值为 0,很可能是不必要的,尤其在申请空间较大的情况下,尤其是一些老的编译器可能不会做这样的优化。
        2
    zhuangzhuang1988   40 天前
    实际上你看开源的库都是有个自己 Memory 包装的
    里面想怎么玩怎么玩
        3
    zmj1316   40 天前 via Android
    性能 填 0 也没什么意义
    vs 里面 debug 下默认就是填 0xcc 更不容易搞错
        4
    pkookp8   40 天前 via Android   ♥ 1
    我觉得大家学习的时候第一个接受到的是 malloc,并且被教导使用未初始化的内存是很危险的,这个可能也是一个原因,所以大家常用 malloc
    malloc 是 memory alloction,也比较好记
    平时看到代码中也有 malloc+memset 的写法,应该是写的人不知道 calloc 的功能
    其实现代编译器和芯片不会真的因为 malloc+memset 改成 calloc 性能就上升一大截,如果是的话还是从考虑优化代码角度考虑
        5
    msg7086   40 天前 via Android
    甚至 memset 可以用优化过速度更快的版本。
        6
    kingcos   40 天前 via iPhone
    有同样的疑问。
        7
    autogen   40 天前
    所以才会有红红火火恍恍惚惚烫烫烫烫烫。。。。
        8
    wheeler   39 天前   ♥ 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   39 天前
    书上和老师这么教的。
        10
    0x11901   39 天前
    @zmj1316 讲道理 calloc 相比 malloc memset 性能更高,但主要看编译器实现,理论上是一样的
        11
    pwrliang   39 天前
    我认为大多场景都是申请空间,然后灌满,再读取多次。主动填 0,会不会在大多数场景都影响性能?
        12
    urmyfaith   39 天前
    在需要填 0 的时候,就是用 calloc;

    在不关系初始值,或者明确会覆盖的话,直接 malloc 不是更省操作.
        13
    urmyfaith   39 天前
    另外,很多人可能不知道有 calloc 这个东西.

    导致 malloc + memset 或者 malloc + bzero 之类的.
        14
    xdeng   39 天前
    当你明确知道要用多大空间覆盖多少内容的时候,申请时去填 0 简直是多此一举。
        15
    zycpp   39 天前 via iPhone
    C 语言的大原则是程序员知道自己在干什么,
    在这个前提下,也就没必要初始化了,
        16
    junkman   39 天前   ♥ 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   39 天前
    performance agin -> performance gain
        18
    xuddk727   39 天前
    做下位机开发的不知道什么情况,我只知道桌面开发一般都会有自己的内存分配策略,因为一些情况下可能得根据分页情况做性能优化,另一种是使用内存池,所以很少见,当然不是没有人用,不然何来屯屯屯屯屯屯和烫烫烫烫烫烫
        19
    africwildman   39 天前
    听了大家讨论,很受教啊。
        20
    wutiantong   39 天前
    @wheeler 感谢分享
        21
    Yggdroot   39 天前
    先问是不是,再问为什么。难道不是 prefer calloc to malloc?
        22
    tigereatsheep   37 天前
    如果让我来实现编译器
    在 32 位的机器上 void *malloc(size_t size) 函数可以简单地把 SP 寄存器中的值加了 size * 4,
    而 void *calloc(size_t nmemb, size_t size) 函数还需要把原 SP~SP+size * 4 地址中的内存值都初始化一下,
    那么 malloc 会快一些,但是一些细心的码农在做编译器的时候可能还会做一些保护之类的事,这样效率就不好说了
        23
    tigereatsheep   37 天前
    说错了,应该是 FP 寄存器。。。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1065 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 22ms · UTC 18:25 · PVG 02:25 · LAX 11:25 · JFK 14:25
    ♥ Do have faith in what you're doing.