2012-02-23 2 views
1

В следующем коде есть memoryleak.Memoryleak при использовании AppDomain.CurrentDomain.AssemblyResolve

class Program 
{ 
    static void Main(string[] args) 
    { 
     for (int i = 0; i < 10; i++) 
     { 
      AssemblyResolveMemoryTest assemblyResolveMemoryTest = new AssemblyResolveMemoryTest(); 
     } 
    } 
} 

class AssemblyResolveMemoryTest 
{ 
    private byte[] _allocateMemory; 

    public AssemblyResolveMemoryTest() 
    { 
     AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 
     //memory is not released anymore 
     _allocateMemory = new byte[300000000]; 
    } 
    System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
    { 
     return null; 
    } 
} 

Похоже, событие AssemblyResolve вызывает утечку памяти.

В чем причина этого? Нужно ли явно удалить обработчик событий в этом случае? Если да, то где именно место для удаления этого обработчика событий? Внедрить IDisposable или использовать Try/finally?

+0

Вам нужно будет подумать, что триста мегабайт. –

+0

Это просто для показа эффекта. Утечка памяти останется, даже если я добавлю только один байт в массив. – Manuel

ответ

3

Да, это событие вызовет утечку памяти. Это потому, что AppDomain.CurrentDomain.AssemblyResolve является статическим, поэтому его жизнь не заканчивается, пока программа не закончится. Таким образом, он должен будет поддерживать ссылку на все обработчики событий, которые были зарегистрированы (+ =), чтобы они оставались в памяти при возникновении события, что приведет к вызову обработчиков.

Я предлагаю вам реализовать IDisposable в классе AssemblyResolveMemoryTest и получить его - = событие.

Затем в цикле for добавьте оператор using, который вызовет вызов dispose.

for (int i = 0; i < 10; i++) 
    { 
     using(AssemblyResolveMemoryTest assemblyResolveMemoryTest = new AssemblyResolveMemoryTest()) 
     { 
     } 
    } 

Вы можете хранить экземпляры assemblyResolveMemoryTest в списке и написать второй цикл, который идет круглый вызова Dispose на них перед тем существует программа. В этом нет особого смысла, потому что, когда ваша программа существует, все будет утилизировано, и «просочившаяся память» будет освобождена.

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

Я предполагаю, что буфер не то, что у вас есть в реальной программе, и вы просто используете его, чтобы продемонстрировать проблему. Возможно, если у вас есть память, на которую ссылается ваш реальный эквивалентный объект assemblyResolveMemoryTest в производственном коде, вы можете попробовать и реструктурировать свою программу, чтобы обработчик событий для AssemblyResolve не был частью объекта, который хранится в другой памяти, которая не имеет отношения к обработка события.

В качестве обработчика события можно использовать статический метод, так что в памяти не останется объектов-членов класса, так как на самом деле вам не понадобится создавать экземпляр класса.

+0

У нас есть этот memoryleak в производстве при использовании его на winform с elementhost/xaml, который открыт/закрыт много. Это вызывает около 10 мб утечки каждый раз. Но я буду использовать для этого статический обработчик событий. – Manuel

Смежные вопросы