2015-03-04 1 views
3

Я испытываю странную память в моей программе с окнами Windows, которая происходит все время на медленных ПК, и когда форма Windows теряет фокус или иначе прерывается быстрее ПК.Проблема с накоплением памяти с помощью Aforge и Windows Forms

В программе, которую я написал, используется Aforge для получения изображений с моей веб-камеры, которые затем я показываю в элементе управления изображениями в Ангоре (CurrImagePic в коде) в форме окна. Изображения переключаются в окно изображения, а затем располагаются на собственной частоте кадров камеры, поэтому он отображается как видео для пользователя, а не для неподвижных изображений. Поле с картинкой - 1080x1920, но пространство для него в форме меньше, поэтому я разрешаю пользователю прокручивать изображение.

После примерно 30 секунд бесперебойной работы на более медленных ПК проблема начинается. На более быстрых ПК проблема возникает только при удержании стрелок прокрутки или нажатии и перетаскивании по любой полосе прокрутки, а также при блокировке ПК или вызове меню Ctrl + Alt + Delete.

Проблема заключается в том, что память, используемая программой, начинает увеличиваться в очень больших кусках, что приводит к сбою памяти. Это невозможно остановить на более медленных ПК, но на более быстрых ПК, если вы перестанете прокручивать или возвращать из меню блокировки/Ctrl + alt + delete, программа стабилизируется с более высоким уровнем использования памяти. Память, которая была начислена во время прокрутки или в меню блокировки, никогда не собирается сборщиком мусора. Я даже пытался вставить кнопку, которая принудительно вызывает GC.collect() при нажатии, и это не уменьшает использование этой памяти.

Я запустил perfmon и обнаружил, что увеличение памяти происходит на неуправляемой куче, но я не знаю, исходит ли оно из растровых изображений, которые не расположены или от чего они могут быть. Отследить его невозможно, так как это не происходит, за исключением вышеуказанных условий. Я пробовал различные решения (например, перенос обработки изображений из обработчика событий и даже использование как глобальных флагов, так и оператора «блокировки», чтобы убедиться, что только один поток или кадр может получить доступ к методу обработки и отображения изображений во время , но я не видел никаких изменений. Фактически, сейчас я вижу некоторые необъяснимые небольшие скачки в использовании памяти, которые я не видел, прежде чем я включил блокировку и переместил обработку из обработчика.

Кто-нибудь запускал в таких ситуациях, как это? Я в недоумении за то, что мне нужно исправить, и я не получаю большую помощь на форумах Aforge. Я думаю, что проблема основана на моем обработчике событий Aforge и методе обработки изображений, если он находится в моем коде на всех - но у меня также есть подозрение, что это что-то более глубокое в коде формы Windows, которое я либо неправильно использую, либо не может выполнить требования моего кода. Код ниже:

//Applicable Globals to this code snippet 
private bool ALLOWFRAME = true; 
private Object FRAMEKEY = new Object(); 
private VideoCaptureDevice COMPVID; 
private Bitmap TMPLTCAP; 
private System.Drawing.Image OLDIMAGE; 
private bool RCRDPIC = false; 

private void COMPVID_NewFrame(object sender, NewFrameEventArgs eventArgs) 
     { 
      //Only process a frame when another is done processing 
      if (ALLOWFRAME == true) 
      { 
       ALLOWFRAME = false; 
       Bitmap PassFrame = AForge.Imaging.Image.Clone(eventArgs.Frame); 
       ProcessFrame(PassFrame); 
       PassFrame.Dispose(); 
      } 
     } 

private void ProcessFrame(Bitmap frameIn) 
     { 
      lock (FRAMEKEY) 
      { 
       if (OLDIMAGE != null) { OLDIMAGE.Dispose(); } 
       //Call comparison method if flag is set. 
       if (COMPON == true) 
       { 
        Difference TmpltFilter = new Difference(TMPLTCAP); 
        TmpltFilter.ApplyInPlace(frameIn); 

        OLDIMAGE = CurrImagePic.Image; 
        CurrImagePic.Image = AForge.Imaging.Image.Clone(frameIn); 
        OLDIMAGE.Dispose(); 
       } 
       else 
       { 
        OLDIMAGE = CurrImagePic.Image; 
        CurrImagePic.Image = AForge.Imaging.Image.Clone(frameIn); 
        OLDIMAGE.Dispose(); 
        //Toggle the flag back to false to show it's safe (i.e., comparisons have stopped) 
        //for the result-recording method to copy from the picture box if it is attempting to copy 
        if (RCRDPIC == true) 
        { 
         RCRDPIC = false; 
        } 
       } 
       ALLOWFRAME = true; 
      } 
     } 
+0

Является ли COMPON истинным или ложным? Может ли это случиться из-за пропуска кадра? Aforge создает фрейм и вызывает событие, однако конкретный кадр не отображается и поэтому никогда не удаляется? Я не могу вспомнить, очищается ли Афанг после себя. – Jens

+0

COMPON прав, если кто-то нажал кнопку «сравнить изображения» в форме окна. До сих пор я наблюдал проблему с COMPON == false, но я уверен, что она будет вести себя одинаково с COMPON == true. Единственной разницей в ветвях является работа разностного фильтра. Если бы это был пропущен кадр, разве мой глобальный локаут в методе обработки просто не запустил бы фрейм? Кроме того, почему кадр пропускается только при захвате полосы прокрутки? – GrayBoard

+0

'frameIn' уже создан aforge перед блокировкой. Если вы просто назначили 'frameIn' вашему кадру без клона, он все еще работает? Если да, то Aforge не избавляется от самого растрового изображения, поэтому они будут наращиваться, даже если вы не используете один из фреймов. – Jens

ответ

0

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

Кроме того, в Timer_Tick случае, попытайтесь сделать следующее:

this.Timer.Stop(); 
Bitmap image = null; 
var temp = this.PictureBox.Image; 

lock (FRAMEKEY) 
{ 
    if (this.ImageQueue.Any()) 
    { 
     image = this.ImageQueue.Dequeue(); 
     if (temp != null) { temp.Dispose(); } 
    } 
} 

this.PictureBox.Image = image; 
if (temp != null) { temp.Dispose(); } 

this.Timer.Start();