繁体   English   中英

结构/值类型的内存分配和取消分配

[英]struct/value type memory allocation and deacllocation

最近,我阅读了Jon Skeet的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" 进入代码,我发现afterbefore相同。 因此struct是一个值类型,它是从堆栈中分配的。 对? 例外,当我检查寄存器时,“ ESP ”完全没有变化。 所以它不是从堆栈分配的?

查看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. 
}
  1. 当分配引用类型的Array时,在函数内部。对数组本身的引用可以存储在预分配的堆栈帧中(即4/8字节表示32/64位)。 1000个元素的实际分配在堆上 ,每个元素又分配 4/8个字节。 此外,您调用new Pixel()会分配class的实例,并且由于它们的引用已存储在数组中而保持活动。

  2. 当您将其更改为函数内部的值类型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数组,则可能更容易考虑整个问题。除了它们的大小不同之外, intPixel (定义为struct)之间的机制相同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM