首页 > 解决方案 > 为什么堆分配比堆栈分配使用大量内存?

问题描述

我想知道为什么堆栈分配比堆分配使用更少的内存?这个分配之间的差距真的很大。当我使用堆栈时。它消耗大约 77MB,但是当我使用堆分配时。它消耗〜880MB。没有内存泄漏(我猜),因为在我删除这个对象后,内存完全返回(回到小于 1KB,就像调用这个函数之前一样)。

这是堆栈分配〜77 MB

void LoadZone() //this fuction is called over 700 times
{
    FILE* file; //this file contains data in binary (~54KB)
    std::string filepath = "./map/" + std::to_string(MapId); //private member int MapId

    errno_t e = fopen_s(&file, filepath.c_str(), "rb");

    fread(&XLength, 1, sizeof(short), file); //private member short XLength
    fread(&YLength, 1, sizeof(short), file); //private member short YLength

    MapGrid.reserve(YLength); //private member : MapGrid is std::vector<std::vector<GridPos>>
    for (short y = 0; y < YLength; ++y)
    {
        //GridPos contains short X,Y  char Value
        std::vector<GridPos> data;
        data.reserve(XLength);
        for (short x = 0; x < XLength; ++x)
        {
            data.emplace_back(x, y, (char)std::getc(file));
        }
        MapGrid.push_back(data);
    }

    fclose(file);
}

这是堆分配 ~880 MB

void LoadZone() //this fuction is called over 700 times
{
    FILE* file; //this file contains data in binary (~54KB)
    std::string filepath = "./map/" + std::to_string(MapId); //private member int MapId

    errno_t e = fopen_s(&file, filepath.c_str(), "rb");

    fread(&XLength, 1, sizeof(short), file); //private member short XLength
    fread(&YLength, 1, sizeof(short), file); //private member short XLength

    MapGrid.resize(YLength); //private member : MapGrid is std::vector<std::vector<GridPos*>>
    for (short y = 0; y < YLength; ++y)
    {
        //GridPos contains short X,Y  char Value
        std::vector<GridPos*> data;
        data.resize(XLength);
        for (short x = 0; x < XLength; ++x)
        {
            data.push_back(new GridPos(x, y, (char)std::getc(file)));
        }
        MapGrid.push_back(data);
    }

    fclose(file);
}

标签: c++memory

解决方案


堆分配都与某个最小值对齐(请参阅 参考资料_STDCPP_DEFAULT_NEW_ALIGNMENT__)。例如,对于 x86_64 上的 glibc,它通常为 16。这基本上意味着堆始终分配至少 16 个字节,即使您要求一个字节。通常会浪费一些字节。因此,当您在堆栈上分配多个对象时,它们可以在内存中彼此相邻放置,但这不适用于堆分配的数据。

其次,堆需要一些管理数据。同样,对于 glibc 和 x86_64,这通常是 16 个字节。

总而言之,如果您分配一个int需要 4 个字节的对象,那么堆为此分配消耗 32 个字节的内存。您可以简单地对此进行基准测试(分配 100M 个整数并测量最大 RSS)。


推荐阅读