C 中分配的内存在什么范围内为零?

问题描述 投票:0回答:2

我的代码需要处理包含多个字符串的大量结构。

实际上,整个数组将包含大约 25k 个结构,每个结构的大小约为 256 字节,因此整个数组需要大约 6 MiB 的堆空间。

// example
struct element {
    char foo[32];
    char bar[16];
    ...
}; // sizeof(struct element) = 256

我担心

calloc
的性能,因为它会将所有内存清零,而且我不需要初始化每个字节。所以我就这么做了
element_arr = malloc(num_elements * sizeof(struct element))

我在运行时分配数组,因为我在编译时不知道

num_elements

为了让我的代码正常工作,我实际上只需要每个成员的第一个字节(

foo
bar
等)为零,其余部分可以保持未初始化。

假设每个结构有 8 个字符串成员,所以我只需要 3% 的清零字节,其他 97% 的清除字节都是浪费,因为它们最终会被真实数据覆盖)。

我看到几个选项:

  1. 立即将所有内容归零,例如与

    calloc
    这确实(我希望)使 使用向量指令写入大块对齐的 零。

  2. memset
    每个 256 字节大小
    struct element
    ,然后用实际数据填充。

  3. 在使用之前,
  4. struct element
    的每个成员分配0。 (
    *element->foo = 0; ...
    ) 这转化为一系列
    mov
    指令,并在
    -O3
    进行优化。 语言方面写起来很麻烦(但是可以处理)。

        mov     byte ptr [rdi + 152], 0
        mov     byte ptr [rdi + 208], 0
        mov     byte ptr [rdi + 200], 0
        mov     byte ptr [rdi + 128], 0
        ...

arm64 看起来类似。

  1. element_arr
    的大小(例如 64 MiB)做出非常保守的假设,将其放置在内存的零初始化部分。 (操作系统需要将我的内存清零)

char element_arr[64 * 1000 * 1000] = {0};
(检查
num_elements < 250000
以确保)

选择什么选项有区别吗? 你有什么建议?

c performance memory dynamic-memory-allocation zero
2个回答
0
投票

您可能太早考虑优化了。进行计算以仅初始化部分内存,或手动调用

memset()
,很容易比仅调用
calloc()
慢很多。

如果您分配 6MiB 内存,则几乎肯定会超过

M_MMAP_MAX
(默认为 64KiB),因此内存将直接来自专用
mmap()
调用,并且一开始就已经被清零,无需做任何事情的需要。因此,在这里使用除
calloc()
之外的任何内容很可能没有意义。

仅当您使用某些外来的 libc 实现时才进行选择性清零,并执行适当的基准测试以确定其性能。如果您使用 glibc、musl 和其他主要 C 库,您应该避免在如此大的分配上手动归零并使用

calloc()
M_MMAP_MAX
将保证
mmap()
的内存归零。


0
投票

你有什么建议?

设置测试硬度来评估性能,然后对各种代码选项进行评级。

如果不分析代码,仍然存在许多依赖于实现的问题。考虑一下操作系统可能会在空闲时间将内存池清零。例如。代码执行

scanf()
调用并等待输入。在此期间,也许兆字节的内存会被清零以供以后使用 - 有效地使程序花费零额外的时间来实现零内存。操作系统甚至可能使用程序启动之前创建的池中的清零内存。
即使 

calloc()

也不一定会使用内存

,因为真正的使用可能会推迟到代码访问内存为止。

© www.soinside.com 2019 - 2024. All rights reserved.