GC.AddMemoryPressure - PullRequest
       20

GC.AddMemoryPressure

6 голосов
/ 11 апреля 2010

Я пишу приложение на C #, использующее стороннюю COM DLL, эта dll создает много ресурсов (таких как растровые изображения, видео, структуры данных) в неуправляемой памяти. Во время копания я наткнулся на следующий призыв к сборщику мусора:

GC.AddMemoryPressure(long long bytesAllocated)

Это задокументировано в MSDN здесь:

http://msdn.microsoft.com/en-us/library/system.gc.addmemorypressure.aspx

Это звучит как то, что я должен вызывать, так как этот внешний dll создает много ресурсов, о которых CLR не знает.

Полагаю, у меня есть два вопроса ...

  1. Как узнать, какое давление на память нужно добавить, когда dll является сторонним, и я не могу точно знать, сколько памяти выделяет эта dll.
  2. Насколько важно это сделать?

Ответы [ 4 ]

5 голосов
/ 11 апреля 2010

В любом смешанном нативном / управляемом процессе существует смесь использования нативной / управляемой памяти. Если между ними нет контролируемых GC отношений, то в этом API не будет необходимости. Например, если в управляемом коде имеются определенные детерминированные изменения состояния, которые приводят к выделению и освобождению собственной памяти, то ничто из того, что может сделать GC, никогда не приведет к освобождению собственной памяти.

Однако очень часто в собственных управляемых объектах, содержащих финализаторы, имеется собственная память. Таким образом, GC может уменьшить размер собственной кучи, просто запустив коллекцию и запустив эти финализаторы.

Поэтому, если у вас много такого происходит, вполне может быть необходимо вызвать этот API (как сказано в документации).

Что касается того, сколько вы должны сказать, это, вероятно, не то, на что вы можете придумать ответ с помощью чистого анализа, особенно с помощью сторонней библиотеки. Вам нужно запустить Performance Monitor, запустить тест, который выделяет много сторонних объектов, и посмотреть на счетчики памяти собственных байтов и CLR, чтобы увидеть, как они связаны.

Поскольку вы используете COM-объект, вы фактически можете принудительно принудительно очищать экземпляры, когда знаете, что они вам больше не нужны, используя Marshal.ReleaseComObject . Обратите внимание, что вам нужно использовать тупой цикл, чтобы избавиться от объекта:

while (Marshal.ReleaseComObject(obj) != 0) 
{
}
3 голосов
/ 11 апреля 2010

Допустим, у меня есть такой объект:

public class SomeImageType : IDisposable
{
    public int Width { get; private set; }
    public int Height { get; private set; }
    public PixelFormat PixelFormat { get; private set; }
    IntPtr ImageData { get; private set; }
    // implementation of constructor and IDisposable not shown
}

Сколько памяти это занимает? 20 байтов + объектные издержки? Когда приходит время для сбора, если этот объект не имеет ссылок, это вообще не имеет значения. Но это займет 20 байтов? Черт, нет - это изображение. Итак, возьмите эти 20 и умножьте их на ширину, высоту и количество байтов на пиксель, и у вас есть что-то, что занимает (возможно) мегабайт. Говоря GC добавить давление памяти, вы говорите, что там есть айсберг, жующий ресурсы. Когда вы утилизируете объект, вы, конечно, освободите эту память и попросите сборщик мусора сбросить это давление. Эти два вызова позволяют вам намекнуть GC, что в круге K есть странные вещи, и, возможно, он хотел бы запланировать сбор по-другому.

2 голосов
/ 11 апреля 2010

Самое важное, что вы можете сделать, это вызвать метод Dispose () этих сторонних классов DLL и быть абсолютно фанатичным в этом. (Или, конечно, используя блоки «using», так как они вызывают Dispose () автоматически при выходе из блока.)

Суть неуправляемых ресурсов в том, что классы .NET, которые обертывают или используют их, должны иметь финализатор, а также реализацию шаблона IDisposable (). Если вызывается Dispose (), он должен немедленно позаботиться о неуправляемых ресурсах, а также подавить финализатор. Если вы не вызываете Dispose (), то у вас есть реальные проблемы с памятью, и добавление «давления» в сборщик мусора не исправит это.

Основная логика сборщика мусора заключается в том, что ни один класс, имеющий активный финализатор, не рассматривается, пока все другие возможности уже не исчерпаны. Это означает, что очистка gen0, gen1 и gen2 уже произошла. Финализатор, который не был подавлен, почти так же плох, как утечка памяти.

Так что вызывайте Dispose (). Убедитесь, что вы никогда не пропустите это.

РЕДАКТИРОВАТЬ: Только что заметил, что сторонняя DLL является COM DLL. Рекомендуется убедиться, что ваши оболочки .NET полностью реализуют IDisposable () (а не просто предоставляют метод Dispose). Затем убедитесь, что вы всегда вызываете Dispose () после завершения работы с COM-объектами.

1 голос
/ 11 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...