Утечка памяти в C # WPF

1

Мне нужно уменьшить утечку памяти в С# WPF после удаления всех используемых объектов. Но я не мог полностью уменьшить потребление памяти, используя следующий фрагмент кода.

Вот мой код:

string str;
Uri uri;
private void Button_Click(object sender, RoutedEventArgs e) // "Load" Button
{
    if(img.Source!=null)
    Unload();    
    str = "F://Photos//Parthi//IMG_20141128_172826244.jpg";   // File Size: 0.643 MB            
    uri = new Uri(str);
    img.Source = new BitmapImage(uri);                         
}

private void Button_Click_1(object sender, RoutedEventArgs e) //"Unload Button"
{
    Unload();
}

private void Unload()
{
    Bitmap bmp = GetBitmap(img.Source as BitmapSource);
    bmp.Dispose();
    bmp = null;
    img.Source = null;           
    str = string.Empty;
    uri = null;
}
private Bitmap GetBitmap(BitmapSource source)
{
    Bitmap bmp = new Bitmap(source.PixelWidth, source.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    source.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
    bmp.UnlockBits(data);
    data = null;
    source = null;
    return bmp;
}

После запуска образца, проверяя его в диспетчере задач, произвело следующее чтение потребления памяти,

Перед нажатием кнопки "Загрузить": 10,0 МБ

После нажатия кнопки "Загрузить": 47,8 МБ

После нажатия кнопки "Разгрузка": 26,0 МБ

После разгрузки мне нужно уменьшить память до 10,0 МБ. Поэтому, пожалуйста, помогите мне в этом.

Заранее спасибо.

  • 0
    вызовите GC.Collect() в конце функции Unload
  • 0
    Bitmap наследуется от Image , которое реализует IDisposable ... почему бы просто не воспользоваться этим и использовать using ? Кстати, почему у вас такое строгое требование, что вы не можете позволить WPF и .NET заботиться о памяти за вас? Я могу ошибаться, но я чувствую, что C или C ++ могут быть лучшим выбором, если вы хотите такой уровень микроуправления.
Показать ещё 4 комментария
Теги:
wpf
memory-leaks

4 ответа

2

Прежде всего, не используйте диспетчер задач для просмотра вашего использования памяти, поскольку он отображает только память, которую выделяет процесс Windows. Там есть много гораздо лучших инструментов, и даже Performance Monitor, который поставляется в Windows, даст вам лучшее представление о производительности вашего приложения и утечке памяти. Вы можете запустить его, запустив perfmon.exe.

В этом примере приложения GC не становится агрессивным с коллекциями до тех пор, пока куча не достигнет примерно 85 МБ. И зачем мне это хотеть? Это не так много памяти, и он очень хорошо работает как решение для кеширования, если я снова захочу использовать те же объекты.

Изображение 174551

Поэтому я предлагаю взглянуть на этот инструмент. Это дает хороший обзор того, что происходит, и это бесплатно.

Во-вторых, только потому, что вы вызывали .Dispose() чтобы освободить эти ресурсы, не означает, что память сразу же выпущена. Вы в основном делаете его подходящим для сбора мусора, и когда GC доберется до него, он позаботится об этом.

Поведение коллекции мусора по умолчанию для приложения WPF: Concurrent (<4.0)/Background (4.0 = <) Workstation GC. Он работает в специальном потоке и большую часть времени пытается запустить одновременно с остальной частью приложения (я говорю большую часть времени, потому что время от времени он будет крайне ненадолго приостанавливать другие потоки, чтобы он мог завершить очистку). Это не дожидаясь, пока вы потеряете память, но в то же время она выполняет сбор только тогда, когда она не сильно влияет на производительность - вроде сбалансированного компромисса.

Еще один фактор, который следует учитывать, заключается в том, что у вас есть файл в формате 0.643 MB и как только вы подсчитываете в BitmapImage, это немного больше... ну, что-то выше 85,000 bytes считается крупным объектом и, следовательно, оно помещается в поколение 2, который содержит кучу больших объектов. Сбор мусора поколения 2 является дорогостоящим и выполняется нечасто. Однако, если вы используете.NET 4.5.1, и я не уверен, что вы находитесь, вы можете заставить уплотнение:

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collection();

Как и в случае с .Dipose(), это не происходит сразу, поскольку это дорогостоящий процесс, и это займет немного больше времени, чем генерация 1 менее чем за миллисекунду. И, честно говоря, вы, вероятно, даже не выиграли бы от этого, так как я сомневаюсь, что у вас будет высокая фрагментация в LOH с этим приложением. Я только что упомянул об этом, чтобы вы знали об этом, если вам когда-нибудь понадобится.

Итак, почему я даю вам краткий урок по поведению GC по умолчанию приложения WPF (и большинство приложений.NET, если на то пошло)? Ну, важно понять поведение ГК и признать его существование. В отличие от приложения C++, где вам предоставляется большой контроль и свобода по распределению памяти, приложение.NET использует GC. Компромисс заключается в том, что память освобождается, когда она освобождается GC. Могут даже быть моменты, когда он освобождает его преждевременно, с вашей точки зрения, и что, если вы явно сохраните объект живым, вызвав GC.KeepAlive(..). Многие встроенные системы не используют GC, и если вы хотите очень точный контроль над своей памятью, я также предлагаю вам не делать этого.

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

2

Использование платформы.net не имеет контроля над памятью, как если бы она работала в c/С++. Сборщик мусора управляет очень сложными политиками, а тот факт, что вы видите память до 26, но 10, является нормальным. .Net резервирует пространство для пополнения более быстрых данных и гарантирует свободное пространство в основной памяти, не требуя постоянной ОС.

То, что я заметил, совершенно нормально. Это вопрос, который в прошлом я лично подвергал Microsoft MVP во время курса

Просмотрите это: http://msdn.microsoft.com/en-us/library/ee787088%28v=vs.110%29.aspx

и это: лучшая практика для принудительного сбора мусора в С#

0

Ваш Unload метод вызывает GetBitmap, но GetBitmap возвращает новый объект каждый раз, так что, насколько я могу судить, вы никогда на самом деле будете распоряжаться img.Source правильно

0

попробуйте управлять использованием ваших переменных. вы можете сделать что-то вроде этого:

private void Button_Click(object sender, RoutedEventArgs e) 
{
  img.Source = new BitmapImage(new Uri(@"F://Photos//Parthi//IMG_20141128_172826244.jpg"));                         
}

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

Надеюсь, поможет

  • 1
    Это будет выделять равное количество памяти. Как только вы создаете экземпляр объекта, он выделяет память. Неважно, встроен он или нет. Область действия этой переменной - метод. Таким образом, эта память будет освобождена только после завершения метода (и для случая, когда удаление вызывается для объекта, когда это одноразовый объект.)

Ещё вопросы

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