Распределение и освобождение памяти типа структуры / значения

1

В последнее время я читаю блог Джона Скита, рассказывающий об объекте и объектах объекта С#. Я написал следующий код, чтобы воспроизвести его эксперимент.

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 - тип значения, он выделяется из стека. Правильно? Кроме того, когда я проверяю регистры, " 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. 
}
  • 0
    и это значит?
Теги:
memory
memory-management

1 ответ

2
Лучший ответ
  1. Когда вы выделяете Array ссылочных типов, внутри функции. Ссылка на сам массив может храниться в предварительно выделенном кадре стека (т.е. 4/8 байт для 32/64 бит). Фактическое распределение для 1000 элементов находится в куче, опять 4/8 байт на элемент. Кроме того, экземпляры класса выделяются при вызове new Pixel() и сохраняются в живых, поскольку их ссылка сохраняется в массиве.

  2. Когда вы меняете его на Array типов значений, внутри функции. Ссылка на сам массив может храниться в предварительно выделенном стеке стека (т.е. 4/8 байт для 32/64 бит). Фактическое распределение для 1000 элементов находится в куче, размер x байтов на элемент, где x - размер типа значения. Любое значение, присвоенное элементу массива, копируется, каждый байт. Ничто не ссылается на элемент массива.

Поскольку вы выделяете массив типов значений, перед вызовом before = GC.GetTotalMemory(true); , до и после не видят разницы в распределении.

Иными словами, в случае классов выделение находится в строке array3[i] = new Pixel(); (в куче), но в случае структуры, выделение находится в строке var array3 = new Pixel[size]; Для структуры new Pixel(); использует небольшое пространство в стеке, но затем вы копируете это значение в предварительно выделенное пространство для массива в куче... и, скорее всего, повторно используете это пространство стека с каждой итерацией.

Может быть, легче думать обо всем, если вы думаете о массиве int вместо массива Pixel. За исключением их разницы в размере, механизм между int и Pixel (определенный как struct) будет таким же.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню