Ali*_*hat 7 c# memory-management
我将拥有一些MyClass类的数千万个实例,并希望最小化其内存大小.在查找.net对象的大小时讨论了测量对象在内存中占用多少空间的问题 我决定遵循Jon Skeet的建议,这是我的代码:
// Edit: This line is "dangerous and foolish" :-)
// (However, commenting it does not change the result)
// [StructLayout(LayoutKind.Sequential, Pack = 1)]
public class MyClass
{
public bool isit;
public MyClass nextRight;
public MyClass nextDown;
}
class Program
{
static void Main(string[] args)
{
var a1 = new MyClass(); //to prevent JIT code mangling the result (Skeet)
var before = GC.GetTotalMemory(true);
MyClass[] arr = new MyClass[10000];
for (int i = 0; i < 10000; i++)
arr[i] = new MyClass();
var after = GC.GetTotalMemory(true);
var per = (after - before) / 10000.0;
Console.WriteLine("Before: {0} After: {1} Per: {2}", before, after, per);
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
我在64位Windows上运行程序,选择"发布",平台目标:"任何cpu",然后选择"优化代码"(选项只有在我明确定位x86时才有意义)结果是,每个实例的结果是48个字节.
我的计算是每个引用8个字节,加上1个字节的bool加上一些~8byte的开销.到底是怎么回事?这是一个保持RAM价格高和/或让非Microsoft代码膨胀的阴谋吗?好吧,好吧,我想我真正的问题是:我做错了什么,或者我怎样才能最小化MyClass的大小?
编辑:我为在问题中草率而道歉,我编辑了几个标识符名称.我具体而直接的关注是建立一个"2-dim链表"作为稀疏布尔矩阵实现,我可以很容易地在给定的行/列中得到设置值的枚举.[当然这意味着我还必须在课堂上存储x,y坐标,这使得我的想法更不可行]
Eri*_*ert 26
从另一端接近问题.而不是问自己"我怎样才能使这个数据结构更小,并且仍然分配了数千万个?" 问问自己"我怎样才能使用完全不同的数据结构来表示这些数据呢?"
看起来你正在构建一个双向链接的bool列表,正如你所说,它使用的内存比它需要的内存多30到50倍.有什么理由说你不是简单地使用a BitArray来存储你的bool列表吗?
更新:
实际上我试图实现一个稀疏的布尔二维矩阵
那你为什么不首先这么说呢?
当我想制作一个庞大的稀疏布尔二维矩阵时,我构建了一个带有memoized工厂的不可变持久布尔四叉树.如果阵列是稀疏的,或者即使它是密集的但在某种程度上是自相似的,你可以实现巨大的压缩.2 64 x 2 64布尔方形的方阵可以很容易地表示,即使显然是一个真正的数组,这将是比世界上存在更多的内存.
我一直在想着做一系列关于这种技术的博客文章; 我可能会在三月下旬这样做.
简而言之,我们的想法是创建一个抽象类Quad,它有两个子类:Single和Multi."单一"是一个双重身份 - 就像一个单身人士,但只有两个实例,称为True和False.Multi是具有四个子四边形的四边形,称为NorthEast,SouthEast,SouthWest和NorthWest.
每个Quad都有一个整数"级别"; Single的级别为零,并且需要多级n级才能使其所有子级为级别为n-1的四元组.
Multi工厂被记忆; 当你要求它制作一个有四个孩子的新Multi时,它会查询缓存以查看它是否已经成功.如果有,它不会构建一个新的; 它分发了旧的.由于Quads是不可变的,因此您不必担心有人在缓存后更改Quad.
现在考虑一下有多少个存储字(一个字是4或8字节,具体取决于架构)和一个"全部错误"的多级n消耗.级别1"全部为假"多个消耗四个单词用于指向其子级的链接,一个用于级别计数的单词(如果需要,您不需要保持多级中的级别,尽管它有助于调试)和几个单词用于同步块等.我们称之为八个字.(加上False Single quad的内存,我们可以假设它是一个常数的两个或三个单词,因此可以忽略.)
级别2"全部为假"多个消耗相同的八个单词,但其四个子级中的每一个都是相同的级别1多个.因此,2级"全假"多的总消耗量比如说16个字.
3级,4级......等等.64级多路复用的总内存消耗在逻辑上是一个2 64 x 2 64平方的布尔数组,只有64 x 16个内存字!
合理?希望这足以让你前进.如果没有,请在3月下旬查看我的博客.
8 (对象引用) + 8 (对象引用) + 1 (bool) + 16 (header) + 8 (数组本身的引用) = 41
即使它在内部未对齐,每个都会在堆上对齐。所以我们正在寻找至少 48 字节。
我一生都无法理解为什么你想要一个布尔值的链表。它们的列表将占用的空间减少 48 倍,这是在您对每位存储 bool 进行优化之前,这将使其小 384 倍。并且更容易操作。
| 归档时间: |
|
| 查看次数: |
1099 次 |
| 最近记录: |