c++ - 为什么堆分配比堆栈分配使用大量内存?
问题描述
我想知道为什么堆栈分配比堆分配使用更少的内存?这个分配之间的差距真的很大。当我使用堆栈时。它消耗大约 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);
}
解决方案
堆分配都与某个最小值对齐(请参阅 参考资料_STDCPP_DEFAULT_NEW_ALIGNMENT__
)。例如,对于 x86_64 上的 glibc,它通常为 16。这基本上意味着堆始终分配至少 16 个字节,即使您要求一个字节。通常会浪费一些字节。因此,当您在堆栈上分配多个对象时,它们可以在内存中彼此相邻放置,但这不适用于堆分配的数据。
其次,堆需要一些管理数据。同样,对于 glibc 和 x86_64,这通常是 16 个字节。
总而言之,如果您分配一个int
需要 4 个字节的对象,那么堆为此分配消耗 32 个字节的内存。您可以简单地对此进行基准测试(分配 100M 个整数并测量最大 RSS)。
推荐阅读
- excel - 遍历包含图表的工作表,将两个 ChartObjects 复制到另一个工作表中
- kubernetes - Skaffold 1.4.0:“由于同步错误而跳过部署:复制文件:”
- python - Python 读取 .bin 数据并转换为字符串
- sql - MS-Access 中的 LEFT JOIN 与多个匹配条件 (AND(OR)) 陷入困境
- php - PHP缓存 - 我错过了一些明显的东西吗?
- groovy - 将 Groovy 3 YamlBuilder 与包含连字符的 Yaml 一起使用
- javascript - JavaScript 日期中这种非一错误的来源是什么?
- angular - 使用 Route Resolver 时,Angular Universal 不会在视图源中加载我的组件
- javascript - Webpack:将 React 添加到 Flask,500 内部服务器错误
- c++ - 如何在不跳转到声明行的情况下在 GDB 中使用结构化绑定单步执行 C++ 代码?