Есть ли обычная практика, как сделать бесплатную память для сборщика мусора проще в .NET?

StackOverflow https://stackoverflow.com/questions/2714811

Вопрос

Я думал, если есть способ ускорить свободную память в .NET. Я создаю игру в .NET (только управляемый код), где не требуется значительная графика, но все же я хотел бы правильно написать, чтобы не потерять производительность в течение ничего.

Например, полезно ли присвоение нулевого значения объектам, которые больше не требуются? Я вижу это в нескольких образцах через Интернет.

Это было полезно?

Решение

Полезно ли присвоение нулевого значения объектам, которые больше не требуются?

Вообще, нет. Большинство образцов, которые вы увидите в Интернете, которые делают это люди, которые пришли в .NET от VB6, где это была обычная лучшая практика. В .NET, это менее полезно. Если у вас очень длительный метод под управлением, он может позволить сборщику мусора найти объект немного раньше - но если ваш метод так же, что у вас есть другие проблемы.

Вместо этого в .NET вы должны построить короткие методы и определить ваши переменные как можно более поздние в самых маленьких блоках масштаба. Используйте «естественный» срок службы переменной, как определено по объему, но сохраните это естественное короткое время жизни.

Вам следует нет Делать свой собственный сборщик мусора, как указано хотя бы еще один ответ здесь. Это может на самом деле сделать вещи помедленнее. Отказ .NET использует сборщик мусора. Принудив сборку мусора, вы мощь Соберите целевой объект (вы также не можете - нет никаких гарантий с сборкой мусора). Но вы, вероятно, также принудили кучу других объектов, которые вы не можете собрать, еще не хранить в высшем образовании, что делает их сложнее собирать в будущем. Так что просто не делай этого.

Другие советы

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

Так что сначала закончите свою игру, а затем, если это слишком медленно, используйте профилировщик, чтобы найти проблему. Скорее всего, это не будет проблемой памяти.

Большая часть графических объектов, связанных с .NET (изображение и его потомки, графики, ручка, кисти и т. Д.). Если вы собираетесь использовать объект для определенной операции, то еще раз используйте следующий рисунок:

using(var g = Graphics.FromBitmap(bmp))
{
    //Do some stuff with the graphics object
}

Таким образом, это гарантирует, что любые неуправляемые ресурсы будут освобождены, когда они выпадают из-за объема.

Я нахожу распределение объектов в .NET Один из вещей, которые влияют на производительность больше всего. Чтобы обойти это, я использую фабричный шаблон, где я перерабатываю объекты, которые я использовал. Вот простая общая реализация:

internal class ListFactory<T> 
    where T: IRecyclable, new()
{
    private List<T> _internalList;
    private int _pointer;

    public ListFactory()
    {
        _internalList = new List<T>();
        _pointer = 0;
    }

    public void Clear()
    {
            _pointer = 0;
    }

    public int Count
    {
        get
        {
            return _pointer;
        }
    }

    public List<T> InnerList
    {
        get
        {
            return _internalList;
        }
    }

    //Either return T form the list or add a new one
    //Clear T when it is being reused
    public T Create()
    {
        T t;

        //If the pointer is less than the object count then return a recycled object
        //Else return a new object 
        if (_pointer < _internalList.Count )
        {
            t = _internalList[_pointer];
            t.Recycle();
        }
        else
        {
            t = new T();
            _internalList.Add(t);
        }
        _pointer ++;
        return t;
    }
}

Для моего алгоритма маршрутизации линий мне нужно постоянно держать много ценностей как RoutEnode который реализует следующий интерфейс:

public interface IRecyclable
{
    void Recycle();
}

Они постоянно создаются и разрушаются. Чтобы перерабатывать эти объекты, создайте новый завод:

nodeFactory = new ListFactory<RouteNode>();

Когда вам нужен объект, вызовите метод создания:

RouteNode start = nodeFactory.Create();
RouteNode goal = nodeFactory.Create();

Когда вы закончите с объектами в списке, очистите список. Указатель сбрасывается до начала списка, но сами объекты не разрушаются. На самом деле метод рециркуляции называется только тогда, когда объект снова восстановлен. (Вы можете сделать это раньше, если у вас есть другие ссылки на объекты, см. Комментарии ниже)

Это довольно наивная реализация, но это место для начала.

Это может быть полезно в некоторых случаях, чтобы установить объекты в нулевые, которые больше не нужны. Часто это бесполезно или контрпродуктивно, но не всегда. Четыре основных ситуации, когда это может быть полезно:

  • Объекты, содержащие поля, объявленные как «приспособленные» в VB.NET, должны реализовывать iDisposable, и должны ослабить эти поля в методе утилизации. Я не знаю, почему VB.NET не включает в себя хороший способ автоматически обоснования с полями с патентами, но поскольку оно не должно быть очищено вручную.
  • Если локальная переменная содержит ссылку на объект, который на самом деле никогда не будет использоваться снова, но может быть некоторое время, прежде чем код достигнет точки, когда компилятор знает, что переменная не будет использоваться, очистка переменной может разрешить ссылку на быть освобожденным рано.
  • Если в какой-то момент, как известно, массив, который большой или был вокруг в течение некоторого времени, как известно, является бесполезным, и в нем хранятся ссылки на некоторые недавно выделенные объекты, очистка этих ссылок, прежде чем уничтожить все выжившие ссылки на массив, могут позволить вновь созданные объекты, которые будут освобождены намного раньше, чем они иначе.
  • Если объект имеет процедуру доработки и находится в очереди завершения доработки, все объекты напрямую или косвенно ссылаются на него, будут освобождены от сборки мусора. Следовательно, доходные объекты не должны ссылаться на что-то, что не понадобится для доработки.

  • Для этого (и я должен был сделать это с частыми> 50 МБ ассигнованиями), позвоните:

            myObj = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
    

    Я заметил, что след памяти приложения будет значительно уменьшаться. Теоретически, вам не нужно это делать. Однако на практике с 32-битной ОС Windows вы можете получить 2 непрерывных блока> 300 МБ в любой момент времени, и имея это пространство, проведенное множеством небольших распределений или ряд крупных, может означать, что другие крупные ассигнования будут провалиться без необходимости. Сборщик мусора работает на заднем плане, когда он может, но если вы абсолютно должны сделать большие ассигнования прямо сейчас, этот набор строк помогает сделать это возможным для меня.

    Редактировать: от того, что я положил в комментарии, для понижающих скольжениях.

    Если вы прочитали весь Сообщение о сборке мусора от Rico Mariani, Вы отметите, что большие, нечастые, не предсказуемые ассигнования памяти попадают в сценарий № 2. Чтобы нить:

    Правило № 2.

    Рассмотрим звонок GC.COLLECT (), если только что произошедшее неректное событие, и это событие, скорее всего, вызвало много старых объектов, чтобы умереть.

    Классический пример этого - это если вы пишете клиентское приложение, и вы отображаете очень большую и сложную форму, которая имеет много данных, связанных с ним. Ваш пользователь только что взаимодействовал с этой формой, потенциально создавая некоторые большие объекты ... такие вещи, как документы XML, или большой набор данных или два. Когда форма закрывается эти объекты, мертвы и поэтому gc.collect () вернет память, связанную с ними.

    Теперь, почему я предлагаю это как возможное время, чтобы позвонить коллектору? Я имею в виду, мой обычный совет идет что-то вроде «коллектор самоучка, поэтому не связывайтесь с этим». Почему изменение отношения вы можете спросить?

    Ну вот ситуация, когда склонность коллектора [SiC], чтобы попытаться предсказать будущее, основанное на прошлом, вероятно, будет неудачным.

    Если вы делаете большие распределения в вашей игре, вам нужно будет осторожнее о том, как обрабатывается память. Сборщик мусора работает на прогнозе на основе прошлых событий, и большие блоки памяти на 32-битной машине могут быть разрушительными для будущих ассигнований, если он не управляется должным образом. Если вы этого не сделали, не примите автоматически, не думайте, что я ошибаюсь; Если вы это сделали, я бы приветствовал объяснение того, как это сделать должным образом (т. Е. Как сделать мешал памяти, чтобы убедиться, что я всегда могу выделить 50-100 МБ памяти в данный момент времени).

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top