c++ - 每个对象内存分配的开销是多少?

标签 c++ c memory allocation

<分区>

假设,如果我调用 malloc(sizeof(int)),请求 4 个字节,系统(或标准库?)将额外添加多少来支持内存管理基础设施?我相信应该有一些。否则,当我调用 free(ptr) 时,系统如何知道要处理多少字节。

更新 1:这听起来像是一个“过于宽泛的问题”,而且显然是特定于 C/C++ 库的,但我感兴趣的是支持单个分配所需的最小额外内存。甚至不是特定于系统或实现的。比如二叉树,必须有2个指针,分别是左 child 和右 child ,你怎么也挤不进去。

更新 2: 我决定在 Windows 64 上亲自检查一下。

#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <psapi.h>
void main(int argc, char *argv[])
{
    int m = (argc > 1) ? atoi(argv[1]) : 1;
    int n = (argc > 2) ? atoi(argv[2]) : 0;
    for (int i = 0; i < n; i++)
        malloc(m);
    size_t peakKb(0);
    PROCESS_MEMORY_COUNTERS pmc;
    if ( GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)) )
            peakKb = pmc.PeakWorkingSetSize >> 10;
    printf("requested : %d kb, total: %d kb\n", (m*n) >> 10, peakKb);
    _getch();
}

请求:0 kb,总计:2080 kb

1 字节: 要求:976 kb,总计:17788 kb 额外:17788 - 2080 - 976 = 14732 (+1410%)

2 个字节: 要求:1953 kb,总计:17784 kb 额外:17784 - 2080 - 1953 =(超过 +605%)

4 个字节: 要求:3906 kb,总计:17796 kb 额外:17796 - 2080 - 3906 = 10810 (+177%)

8 个字节: 要求:7812 kb,总计:17784 kb 额外:17784 - 2080 - 7812 = (0%)

更新 3:这是我一直在寻找的问题的答案:除了速度慢之外,默认 C++ 分配器的通用性使得它对于小对象的空间效率非常低。默认分配器管理一个内存池,而这种管理通常需要一些额外的内存。通常,簿记内存为每个分配了 new 的 block 增加了几个额外的字节(4 到 32)。如果您分配 1024 字节的 block ,则每个 block 的空间开销是微不足道的(0.4% 到 3%)。如果分配 8 字节的对象,每个对象的开销将变为 50% 到 400%,如果分配许多这样的小对象,这个数字足以让您担心。

最佳答案

对于分配的对象,理论上不需要额外的元数据。例如,malloc 的一致实现可以将所有分配请求集中到一个固定的最大对象大小。所以对于 malloc (25),您实际上会收到一个 256 字节的缓冲区,而 malloc (257) 会失败并返回一个空指针。

更实际的是,一些 malloc 实现在指针本身中编码分配大小,或者直接使用对应于特定固定大小类的位模式,或者间接使用哈希表或多级 trie。如果我没记错的话,Address Sanitizer 的内部 malloc 就是这种类型。对于这样的 malloc,至少部分立即分配开销不是来自添加用于堆管理的元数据,而是来自将分配大小四舍五入到支持的大小级别。

其他 malloc 具有单个单词的每个分配 header 。 (dlmalloc 及其衍生物是流行的例子)。实际的每次分配开销通常稍大一些,因为由于 header 字,您会得到奇怪的支持分配大小(例如 24、40、56 ……在 64 位系统上具有 16 字节对齐的字节)。

要记住的一件事是,许多 malloc 实现放置了大量数据 deallocated 对象(尚未返回给操作系统内核),所以malloc(函数)可以快速找到适当大小的未使用内存区域。特别是对于 dlmalloc 风格的分配器,这也提供了对最小对象大小的限制。使用释放对象进行堆管理也会增加 malloc 开销,但它对单个分配的影响很难量化。

关于c++ - 每个对象内存分配的开销是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46979588/

相关文章:

C++如何在字符后获取子字符串?

c - 从进程 ID 获取窗口标题

c - strtok 中的段错误

C: Hook tshark 以访问数据包的分析层

c - 在c中多次分配同一变量

c - 如何使用 C 获取特定的内存地址

c++ - 有没有办法从特定的内存位置分配内存?

c++ - 我可以在 mac 命令行应用程序与 mac 应用程序之间进行通信吗

c# - 如何在 Visual Studio 中从 C++/CLI 和 C# 调用 C++/CLI?

c++ - 在 C++ 中转发引用和转换构造函数