2

我不明白为什么这个结构占用 96 字节的内存。

struct cell
{
    bool filled;
    bool isParent;
    short int mat;
    bool cx,cy,cz;
    vect norm;
    struct cell* child[8];
    struct cell* parent;
    cell(float pxx=0, float pyy=0, float pzz=0, float ss=0, cell *par=NULL, bool cxx=0, bool cyy=0, bool czz=0);

    void open_read(string);
};

我知道字对齐,但我认为这至少应该不超过 64 个字节......这个结构将有数百万个实例,所以我怎样才能将内存占用降到最低?我正在使用 linux 并且 vect 是一个向量(3 个浮点数)

4

3 回答 3

1

对于指针,您无能为力。

但是,您可以使用一位枚举器或位域将所有布尔值压缩为一个字节。根据 的最大值mat,您可以将标志和该值压缩为两个字节。这不是一个很大的节省。

如果您希望您的树非常密集,则可以通过将您的孩子分配为池来获得显着收益。也就是说,您有一个struct cell* child指针,它引用一个内存块,该内存块是一个由所有八个子元素组成的数组。然后,您可以节省每条记录 7 个指针的空间,并了解每个非叶节点将分配比它需要的更多的内存。您可能需要一个标志来指示节点为空。

或者,如果您想牺牲数组的随机访问,您可以将您的孩子链接为一个列表。然后你只需要一个child指针和一个sibling指针。每个节点节省 6 个指针,并且不会因池化而浪费。不过,它有点笨拙。

于 2013-02-04T23:51:24.860 回答
1

问题显然是 64 位系统上的 8 字节指针

如果你真的想尽量减少内存占用,并且你愿意为实现它而跳舞,我们可以尝试减少指针大小

不建议使用 32 位指针,因为那样您只能访问 4 GB 的内存,如果您使用大量内存,这可能还不够

我可以建议这种有点疯狂的方法:

对于您的结构,使用自定义分配器而不是常规堆。自定义分配器基本上意味着对于此特定结构的实例,您正在使用您自己管理的单独堆。在 Windows 操作系统上,使用 HeapCreate() 很容易做到这一点,在 Linux 上,使用这个问题引用的 mmap:HeapCreate, HeapAlloc in Linux, private allocator for Linux

因为我们为这个结构类型有一个单独的堆,所以这个堆只会分配和释放这个结构的实例。这本身就是一项重大优化,因为具有完全相同大小的所有分配消除了堆碎片。

现在,为了诀窍。由于每个实例都在这个单独的堆中,我们可以给它一个索引。只需取其分配的指针,减去堆起始指针并除以结构大小。堆中的第一个结构将获得索引 0,第二个是索引 1,依此类推。我们要做的是保存结构的索引而不是结构的指针。这些索引更节省空间,并且可以很容易地转换回指针。

这种方法当然只会最小化指向您的单元结构的指针。而不是通用堆中的通用指针。如果你觉得除以结构体大小是危险的(当你这样做时假设所有结构体在堆中都是连续的),跳过这一步,它只会节省几个位。简单地替换堆开始可能足以为您节省大量空间。

有点矫枉过正,但还是很有趣:)

于 2013-02-05T00:11:02.853 回答
0

Talkol 关于使用自定义分配器的建议是一个很好的建议。如果结构将按随机顺序访问,并且您对实现最佳性能感兴趣,那么工作可能会很好,这样您的结构就是字节,并且在 64 字节边界上对齐。数据以称为“行”的 64 字节块的形式从主内存中提取到缓存中;CPU 可以在将块从主内存提取到缓存所需的时间内执行数十或数百条指令。如果结构将按随机顺序访问,则将它们对齐意味着读取每个结构将只需要加载一个缓存行而不是两个。

请注意,如果数据有时会被顺序访问,较小的结构可能会提高效率,因为即使访问一个需要获取两个缓存行,访问下一个也最多需要获取一个;如果一个结构占用 48 个字节,则每组访问的四个结构只需要 3 次高速缓存线提取,但随机访问平均需要 1.5 次高速缓存线提取。

于 2013-02-05T02:30:39.070 回答