最近,我阅读了Jon Skeet's Blog,讨论了C#对象的占用空间和开销。我写了下面的代码来复制他的实验。
class Pixel
{
private byte _r;
private byte _g;
private byte _b;
public int x { get; set; }
public int y { get; set; }
public System.Windows.Media.Color Color
{
get { return System.Windows.Media.Color.FromRgb(_r, _g, _b); }
}
}
static void Main(string[] args)
{
size = 1000;
var array3 = new Pixelsize];
before = GC.GetTotalMemory(true);
for (int i = 0; i < size; i++)
{
array3[i] = new Pixel();
}
after = GC.GetTotalMemory(true);
Console.WriteLine("Pixel is {0} bytes", (after - before) / size);
}
到目前为止,程序报告"Pixel is 15 bytes"
,即8字节基数+4字节+ 1 + 1 + 1 = 15字节。
然后我想知道:struct
实例是否具有与class
实例相同的开销。所以我将Pixel
更改为struct
。
struct Pixel
{
private byte _r;
private byte _g;
private byte _b;
public int x { get; set; }
public int y { get; set; }
public System.Windows.Media.Color Color
{
get { return System.Windows.Media.Color.FromRgb(_r, _g, _b); }
}
}
现在,该计划报告"Pixel is 0 bytes"
。进入代码后,我发现after
与before
相同。所以struct是一个值类型,它是从堆栈中分配的。对?当我检查寄存器&#34; ESP
&#34;根本不会改变。所以它不是从堆栈中分配的?
查看TaskManager,分配后,演示程序的内存使用量增加了8000个字节。这个8000字节来自哪里?
最后,由于GC不知道内存分配,我该如何解除分配内存?我试图将分配代码放在一个块中,并希望当array3超出范围时,这些内存将被释放。但是,内存使用情况没有改变。我在这里得到了内存泄漏吗?
static void Main(string[] args)
{
{
size = 1000;
var array3 = new Pixelsize];
before = GC.GetTotalMemory(true);
for (int i = 0; i < size; i++)
{
array3[i] = new Pixel();
}
after = GC.GetTotalMemory(true);
Console.WriteLine("Pixel is {0} bytes", (after - before) / size);
}
//Expect the memory to be released here, but nothing happened.
}
答案 0 :(得分:2)
在函数内部分配Array
引用类型时。对数组本身的引用可以存储在预先分配的堆栈帧上(即32/64位的4/8字节) 。 1000个元素的实际分配在堆上,每个元素再次为4/8个字节。此外,在调用new Pixel()
时会分配实例类,并保持活动状态,因为它们的引用存储在数组中。
当你在函数内部将它更改为值Array
的值类型时。对数组本身的引用可以存储在预先分配的堆栈帧上(即32/64的4/8字节)位)。 1000个元素的实际分配在堆上,每个元素x个字节的大小,其中x是值类型的大小。分配给数组元素的任何值都会被复制,每个字节都被复制。数组元素没有引用任何值。
由于您在调用before = GC.GetTotalMemory(true);
之前分配了值类型数组,因此在分配之前和之后都没有看到任何差异。
换句话说,在类的情况下,分配在行array3[i] = new Pixel();
(在堆上)
但是在sruct的情况下,分配在var array3 = new Pixel[size];
行
对于结构体,new Pixel();
在堆栈上使用了一点空间,但是然后将该值复制到堆中数组的预分配空间...并且很可能在每次迭代时重用该堆栈空间。
如果考虑int
的数组而不是Pixel
的数组,可能更容易思考整个问题。除了它们的大小差异之外,{{1}之间的机制和int
(定义为struct)将是相同的。