【问题标题】:Wrapping malloc - C包装 malloc - C
【发布时间】:2010-03-19 18:29:27
【问题描述】:

我是 C 初学者。在阅读 git 的源代码时,我在 malloc 周围发现了这个包装函数。

void *xmalloc(size_t size)
{
    void *ret = malloc(size);
    if (!ret && !size)
        ret = malloc(1);
    if (!ret) {
        release_pack_memory(size, -1);
        ret = malloc(size);
        if (!ret && !size)
            ret = malloc(1);
        if (!ret)
            die("Out of memory, malloc failed");
    }
#ifdef XMALLOC_POISON
    memset(ret, 0xA5, size);
#endif
    return ret;
}

问题

  1. 我不明白他们为什么使用malloc(1)
  2. release_pack_memory 是做什么的,我在整个源代码中找不到这个函数实现。
  3. #ifdef XMALLOC_POISON memset(ret, 0xA5, size); 有什么作用?

我计划在我的项目中重复使用此功能。这是 malloc 的一个很好的包装吗?

任何帮助都会很棒。

【问题讨论】:

  • 感谢阅读现有复杂程序的代码 - 我希望更多的开发人员这样做。
  • 对于问题 2:它的定义在 sha1_file.c 中(大概是与 git 的包对象有关的内存),它的原型在 git-compat-util.h 中。 (提示:只要你在看 git 的源代码,使用git grep release_pack_memory 就可以找到它!)
  • @Lars:谢谢。 @Jefromi:关于git grep 的好点。
  • “我是 C 的初学者。在阅读 git 的源代码时...” - 在最深处,太棒了。

标签: c memory-management malloc


【解决方案1】:
  1. malloc(0) 并非在所有平台上都有效,在这种情况下,会改为分配一个字节。允许分配长度为 0 的内存块可以简化程序的高层逻辑。

  2. 不知道。

  3. 通过使用非零值填充分配的内存,可以更容易地发现程序中未正确初始化而使用内存的错误:在这种情况下,程序几乎会立即崩溃。由于填充内存需要时间,因此它被包装在预处理器定义中,因此仅在需要时才编译。

【讨论】:

  • 'malloc(0)' 的行为是实现定义的。它要么返回一个 NULL 指针,要么返回一个指向零字节数据的非空指针(当然,你永远不能取消引用)。 C99 §7.20.3 内存管理函数:“如果请求的空间大小为零,则行为由实现定义:要么返回空指针,要么行为就像大小是某个非零值,除了返回的指针不得用于访问对象。”
【解决方案2】:

对于问题 2:release_pack_memory 在sha1_file.c:570 中找到。

【讨论】:

    【解决方案3】:

    对于问题 1:

    标准没有定义malloc(0) 的行为。这可能会返回一个有效的指针,也可能会返回 NULL。不同的实现以不同的方式处理它,因此代码回退到malloc(1) 以获得一致的行为。

    对于问题 3:

    它将缓冲区的内容设置为“奇怪”的东西。这样,您的代码有望不依赖于特定的内容(malloc 不能保证)。

    【讨论】:

    • 你推荐使用这个包装器吗?
    • @Appu - 将 0 更改为 1 并执行 memset 很好。 OOM 策略的死因取决于您所写的内容。该策略适用于执行一件事并退出的命令行实用程序。对于长期存在的服务器,该策略可能合适,也可能不合适(您是要退出进程还是要清理当前请求并重试)。该策略不适用于通用库,因为 OOM 的策略应由主应用程序决定。
    • 好点。我将要编写的代码是用于库的。所以我想我应该避免die
    • “它应该返回一个没有与之关联的内存的有效指针还是应该返回 NULL?” - 哦,我可以回答,“是的”;-) 不确定您的回答是否清楚地表明实施必须做一个或另一个。如果它是一个有效的指针,那么它每次都是不同的。
    【解决方案4】:

    我不熟悉这个包装器,但这就是它的作用

    1 - 如果指定了 size=0,那么如果底层 malloc 没有这样做,它会分配 1 个字节

    这大概是为了让调用者仍然可以对其进行免费操作(如 realloc)

    2 我假设它试图强制底层内存子系统更努力地寻找内存

    3 XMALLOC_POISON 强制缓冲到已知状态 这是防止和检测未初始化数据引起的奇怪错误的常见做法

    其次 - 为什么要包装 malloc。从你想要做什么的想法开始,然后实现它或复制一个实现。包装 malloc 的原因

    1. 泄漏检测
    2. 使用分析
    3. 内存池
    4. 调试(如 XMALLOC_POISON)
    5. 强制检查

    几乎所有这些都可以使用 valgrind 完成——它的作用远不止于此。

    “编写可靠的代码”书为 1,4 和 5 提供了一套很好的内存包装器

    【讨论】:

    • 感谢您的回答。老实说,我有点迷失在 C 世界中。所以为了避免我犯错误,我正在阅读其他程序的代码并了解它们是如何编写代码的。
    • “这大概是为了让调用者仍然可以对其执行 free 操作” - 您仍然可以在空指针上调用 free 或 realloc。我不知道 git 的来源,但更可能是为了确保调用者可以明确地将 0 返回视为错误,即使输入为 0。或者可能是为了确保指向不同 0- 的指针大小分配比较不同(“这不是你的零大小缓冲区,所以它一定不是你的手提箱!”)。
    猜你喜欢
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 2017-04-04
    • 1970-01-01
    相关资源
    最近更新 更多