Что это за "объект ручки закрепления []", который я вижу в Jetbrains dotMemory, когда использую List<T>?

Я попытался придумать самый простой код, чтобы воспроизвести то, что я вижу. Полная программа приведена ниже, но я опишу ее здесь. Предположим, у меня есть класс с именем ListData это просто имеет некоторые свойства. Тогда предположим, что у меня есть MyList класс, в котором есть член List<ListData> m_list, предполагать m_list инициализируется в MyList конструктор.

В основном методе я просто создаю один из этих MyList объекты, добавить несколько ListData к этому, тогда позвольте этому выйти из области видимости. Я делаю снимок в dotMemory после ListData был добавлен, то я делаю еще один снимок после MyList объект выходит из области видимости.

В dotMemory я вижу, что MyList объект был восстановлен, как и ожидалось. Я также вижу, что два ListData объекты, которые я создал, также были восстановлены, как и ожидалось.

Чего я не понимаю, так это почему ListData[] что выжило? Вот снимок экрана этого:Скриншот этого в dotMemory

Я открываю уцелевшие объекты на новейшем снимке для ListData[] затем я просматриваю ключевые пути сохранения, вот что я вижу.

Ключевые пути хранения

Я новичок в управлении памятью.NET, и я создал этот пример приложения, чтобы помочь мне изучить его. Я скачал пробную версию JetBrains dotMemory версии 4.3. Я использую Visual Studio 2013 Professional. Я должен изучить управление памятью, чтобы я мог исправить проблемы с памятью, которые у нас есть на работе.

Вот полная программа, которая может использоваться, чтобы воспроизвести это. Это просто быстрое и грязное приложение, но оно получит то, о чем я спрашиваю, если вы его профилируете.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{

    class ListData
    {
        public ListData(string name, int n) { Name = name; Num = n; }
        public string Name { get; private set; }
        public int Num { get; private set; }
    }

    class MyList
    {

        public MyList()
        {
            m = new List<ListData>();
        }

        public void AddString(ListData d)
        {
            m.Add(d);
        }

        private List<ListData> m;

    }


    class Program
    {
        static void Main(string[] args)
        {
            {
                MyList l = new MyList();
                bool bRunning = true;
                while (bRunning)
                {
                    Console.WriteLine("a or q");
                    string input = Console.ReadLine();
                    switch (input)
                    {
                        case "a":
                            {
                                Console.WriteLine("Name: ");
                                string strName = Console.ReadLine();
                                Console.WriteLine("Num: ");
                                string strNum = Console.ReadLine();
                                l.AddString(new ListData(strName, Convert.ToInt32(strNum)));
                                break;
                            }
                        case "q":
                            {
                                bRunning = false;
                                break;
                            }
                    }
                }
            }

            Console.WriteLine("good bye");
            Console.ReadLine();
        }
    }
}

шаги:

  1. Постройте приведенный выше код в релизе.
  2. В dotMemory выберите для профилирования автономное приложение.
  3. Перейдите к выпуску exe.
  4. Выберите опцию, чтобы начать сбор данных о распределении немедленно.
  5. Нажмите Run.
  6. Сделайте моментальный снимок и назовите его "раньше". Это до того, как какие-либо ListData были добавлены.
  7. В приложении введите и добавьте два ListData.
  8. В dotMemory, сделайте еще один снимок и назовите его "добавлено 2", потому что мы добавили два ListData.
  9. В приложении введите q, чтобы выйти (MyList выйдет из области видимости). Прежде чем снова ввести Enter, чтобы выйти из приложения, сделайте еще один снимок в dotMemory. Назовите это "вне области".
  10. В приложении введите Enter, чтобы закрыть приложение.
  11. В dotMemory сравните "добавленные 2" и "вне области" снимки. Группировать по пространству имен. Вы увидите ListData[], на который я ссылаюсь.

Обратите внимание на то, что MyList и два объекта ListData собирали мусор, а ListData[] - нет. Почему существует ListData[]? Как я могу заставить его собирать мусор?

1 ответ

Решение

Почему существует ListData[]? Как я могу заставить его собирать мусор?

Если вы посмотрите на "Creation Stack Trace" внутри dotMemory, вы увидите:

dotMemory StackTrace

Это показывает вам, что пустой ListData[0] Экземпляр был создан с помощью статического конструктора List<T>, Если вы посмотрите на источник, вы увидите это:

static readonly T[]  _emptyArray = new T[0];    

List<T> инициализирует пустой массив по умолчанию для оптимизации, чтобы избежать такого распределения при каждом создании нового List<T>, Это конструктор по умолчанию:

public List() 
{
    _items = _emptyArray;
}

Только один вы используете List<T>.AddБудет ли это изменить размер массива.

static ссылки на членов из "Кучи высокой частоты", которые создаются один раз для каждого AppDomain в вашем приложении. Закрепленный object[] вы видите на самом деле место, где все static экземпляры хранятся.

Поскольку экземпляр static, он останется в памяти на время жизни вашего приложения.

Другие вопросы по тегам