结构与类内存开销

本文关键字:开销 内存 结构 | 更新日期: 2023-09-27 18:24:06

我正在编写一个应用程序,它将创建数千个小对象,并将它们递归存储在数组中。通过"递归",我的意思是,K的每个实例都将有一个K实例的数组,这个数组将有K个实例的数组等等,这个数组+一个int字段是唯一的属性+一些方法。我发现,即使是少量数据(约1MB)的内存使用量增长也很快,当我处理的数据约为10MB时,我会得到"OutOfMemoryException",更不用说当它更大时(我有4GB的RAM):)。你建议我怎么做?我想,如果我创建单独的类V来处理这些对象,这样K的实例将只有K的数组+一个整数字段,并将K作为一个结构,而不是一个类,它应该会优化一些东西-没有垃圾收集之类的东西。。。但这有点挑战,所以在我开始全面重写之前,我宁愿问你这是否是个好主意:)。

编辑:好的,一些抽象代码

public void Add(string word) {
    int i;
    string shorter;
    if (word.Length > 0) {
        i = //something, it's really irrelevant
        if (t[i] == null) {
            t[i] = new MyClass();
        }
        shorterWord = word.Substring(1); 
        //end of word
        if(shorterWord.Length == 0) {
            t[i].WordEnd = END;
        }
        //saving the word letter by letter
        t[i].Add(shorterWord);
        }
    }
}

结构与类内存开销

对我来说,在深入研究这一问题时,我已经有了以下假设(它们可能不准确;作为一名程序员,我越来越老了)。类有额外的内存消耗,因为需要引用来寻址它。存储引用,32位编译需要Int32大小的指针。总是在堆上分配(不记得C++是否有其他可能性,我会冒险是吗?)

在本文中找到的简短答案是,Object有一个12字节的基本占用空间+4个可能未使用的字节,这取决于您的类(毫无疑问与填充有关)。

http://www.codeproject.com/Articles/231120/Reducing-memory-footprint-and-object-instance-size

您将遇到的其他问题是数组也有开销。一种可能性是将您自己的偏移量管理到一个或多个更大的数组中。这反过来又越来越接近一种更高效的语言更适合的东西。

我不确定是否有库可以有效地为小对象提供存储。可能是。

我对它的看法是,使用Structs,在一个大数组中管理您自己的偏移量,如果它为您服务,则使用适当的打包指令(尽管我怀疑每次处理不均匀打包的数据时,在运行时会花费一些额外的指令)

[StructLayout(LayoutKind.Sequential, Pack = 1)]

您的堆栈正在爆炸。

迭代而不是递归。

你没有搞砸系统堆栈,你搞砸代码堆栈,10K函数调用会把它搞砸。

您需要适当的尾部递归,这只是一个迭代破解。

确保系统中有足够的内存。超过100mb+等。这真的取决于你的系统。链表中的递归对象就是您要查看的对象。如果您继续递归,它将达到内存限制,并且会抛出nomemoryexception。确保跟踪任何程序的内存使用情况。没有什么是无限的,尤其是记忆。如果内存有限,请将其保存到磁盘中。

看起来您的代码中有无限递归,并且抛出了内存不足的情况。检查代码。递归代码中应该有开始和结束。否则,它将在某个时刻超过10兆字节的内存。

您可以使用更好的数据结构即每个字母可以是一个字节(a-0、b-1…)。每个单词片段都可以被索引,尤其是子字符串-你应该可以用更少的内存(尽管这会降低性能)

只需列出递归算法并清除变量名。如果您正在进行BFS类型的遍历,并将所有对象都保存在内存中,则会耗尽内存。例如,在这种情况下,请将其替换为DFS。

编辑1:

你可以通过估计你将生成多少项目来加快算法,然后一次分配那么多内存。随着算法的进展,填充分配的内存。这减少了碎片化和重新分配&对完整阵列操作进行复制。尽管如此,在完成对这些生成的单词的操作后,应该将它们从数据结构中删除,这样它们就可以进行GC处理,这样就不会耗尽内存。