我想举一个最小的例子。如果提供的代码还不够,请告诉我您还需要什么。这不是什么 super secret ;)
考虑以下两个实现:
使用 3d 数组:
.h
class Grid
{
public:
Grid();
uint8_t get(int x, int y, int z);
void set(int x, int y, int z, uint8_t value);
private:
uint8_t blocks[Chunk::width][Chunk::height][Chunk::depth];
};
.cpp
Grid::Grid()
{
memset(blocks, 0, sizeof(blocks));
}
uint8_t Grid::get(int x, int y, int z)
{
return blocks[x][y][z];
}
void Grid::set(int x, int y, int z, uint8_t value)
{
blocks[x][y][z] = value;
}
现在是一维数组:
.h
class Grid
{
public:
Grid();
uint8_t get(int x, int y, int z);
void set(int x, int y, int z, uint8_t value);
private:
uint8_t blocks[Chunk::width * Chunk::height * Chunk::depth];
int to1D(int x, int y, int z) { return x + (y * Chunk::width) + (z * Chunk::width * Chunk::height); }
};
.cpp
Grid::Grid()
{
memset(blocks, 0, sizeof(blocks));
}
uint8_t Grid::get(int x, int y, int z)
{
return this->blocks[x + (y * Chunk::width) + (z * Chunk::width * Chunk::height)];
}
void Grid::set(int x, int y, int z, uint8_t value)
{
this->blocks[x + (y * Chunk::width) + (z * Chunk::width * Chunk::height)] = value;
}
现在有了 3D 版本,一切都像魅力一样,而对于相同的整体尺寸我得到了
SUMMARY: AddressSanitizer: heap-buffer-overflow src/Grid.cpp:16 in Grid::get(int, int, int)
我真的很想知道为什么会这样。两种实现都包含 uint8_t
...我似乎看不到/无法理解的 3d 数组版本中正在进行什么优化?
(是的,这是我的世界体素引擎实验;))
最佳答案
如果您正在为游戏构建环境,我猜您会遇到内存分配问题。假设您正在运行的游戏需要 50 MB 内存。从任何地方获取 50 MB 都不是什么大问题。但是试图获得 50 MB 的连续内存是 waaaaaayyy 更困难。现在大多数操作系统都使用分页系统来跟踪已分配和未分配的内存。这里有更多信息:https://en.wikipedia.org/wiki/Paging
3D 数组基本上是指向指针数组的指针,其中每个指针都指向另一个指针数组。这些指针中的每一个都包含一个有限的内存块来与之交互。所以在这种情况下,操作系统可以给你 5,000 个 50 KB 的内存块,指针可以将所有这些内存保存在不同的地方。
关于C++ 3D 数组到 1D 导致堆缓冲区溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43056536/