Проблема нехватки памяти в Visual Studio 2010 Visual Basic .Net 4.0 - PullRequest
2 голосов
/ 15 сентября 2011

У меня есть две программы Windows Form, которые представляют собой базу данных изображений и слайд-шоу.Слайд-шоу

постоянно обновляет отображаемую графическую панель без увеличения памяти

, используемой при каждом новом переключении изображения.Тем не менее, у меня есть вторая форма, в которой

имеет 50 коробок с картинками, которые предназначены для отображения эскизов картинок, которые будут добавлены в базу данных.По мере того как размер каждого изображения (57,40) обновляется уменьшенным миниатюрой (<12 КБ), объем памяти, используемой средой IDE, возрастает до чуть более 1 ГБ в моей 32-битной системе XP, с примерно 660 МБ до загрузки любых миниатюрных изображений.. </p>

Поскольку из исходных файлов .jpg размером более 3 МБ загружается около 30 форматов (57,40), ящики памяти увеличиваются до 2,1 ГБ.(Проблема не так легко возникает с изображениями .jpg <= 15 КБ, и все 50 эскизов могут использоваться с использованием <1,3 ГБ памяти). </p>

Проблема проявляется с изображениями со средним размером файла .jpg> 3 МБ на HD. CanonКамера .jpg изображения загружаются в 30 из отображаемых уменьшенных изображений, и я начинаю щелкать по выбранным отображаемым изображениям, и используемая память быстро увеличивается и превышает 2,3 ГБ памяти, вызывающей сбой из-за нехватки памяти.

Этоошибка в VB2010 или .NET 4.0?

Как только все изображения отображаются в виде миниатюр, щелчок мышью на любом из 50 графических блоков на панели, содержащей все миниатюры, обновляет один большой графический блок в самой форме для отображениякартинка в одной картинной коробке размером (1024,768).При щелчке по любой миниатюре в одном большом поле «Изображение» отображается соответствующее изображение из файла, но в то же время системная память увеличивается примерно на 240 КБ на событие щелчка.В конце концов, при> 2,3 ГБ используемой системной памяти программа вылетает с ошибкой «Недостаточно памяти».

Как заставить программу восстановить память, используемую той же самой картинкой, когда

он обновляется только с другой картинкой?

Неполный код ниже:

' Each Thumbnail has a click event
'PB49 is a PictureBox max size (57,40) used as a thumbnail display, all 50 are on a panel
Private Sub PB49_Click(sender As System.Object, e As System.EventArgs) Handles PB49.Click
    'PB(50) is an Integer Array flagging Pictures to add
    If PB(49) = 1 Then PB(49) = 0 Else PB(49) = 1 
    If PB(49) = 1 Then
        CheckBox49.Checked = True       'Tiny Checkbox on thumbnail
        F$ = ListAddFiles.Items(48)     'ListFileBox of FileNames
        PBx1.Image = Image.FromFile(F$) 'Gets filename and path and loads image into PictureBox
        PBx1.Visible = True 'Large PictureBox (1024,768)shows Pic F$ located on Form
    Else
        CheckBox49.Checked = False
        PBx1.Image = Nothing
        PBx1.Visible = False
    End If
End Sub

Я использую Visual Studio Ultimate SP1 updated .NET 4.0 на XP PRO 32-Bit SP3 4GB RAM установлен.

Ответы [ 2 ]

2 голосов
/ 16 сентября 2011

@ AaronLS дал окончательный теоретический ответ, поэтому прочитайте и запомните его.
Утечка памяти в вашем коде находится здесь:

PBx1.Image = Nothing
PBx1.Visible = False

PBx1.Image - Image тип объекта, так как вы используете Image.FromFile метод.И Image является IDisposable, что означает, что он использует собственные ресурсы в неуправляемом коде.

Вы должны явно вызвать метод .Dispose () дляPBx1 в этом коде:

'PBx1.Image = Nothing
If PBx1.Image IsNot Nothing Then PBx1.Image.Dispose() End If
PBx1.Visible = False
2 голосов
/ 15 сентября 2011

Когда вы скрываете изображения, возможно ли, что изображение загружается снова.Т.е. вы прячете его, а скрытый остается там, и он снова добавляется позже.Следовательно, вы накапливаете огромное количество скрытых изображений?

«Утечки памяти» в приложениях .NET часто являются результатом отсутствия обнуления ссылок или удаления объекта из всех коллекций.Пока объект имеет ссылку откуда-либо, какой-либо элемент управления в коллекции элементов управления в форме или одну из ваших собственных коллекций, он будет оставаться в памяти.Я не уверен, что вы используете для показа / скрытия изображения, но, возможно, вам нужно удалить изображение и убедиться, что вы удаляете ссылки на него из всех соответствующих элементов управления.Благодаря тому, как коллекции элементов управления могут быть вложенными, было бы легко пропустить место.Вероятно, существует много дополнительных накладных расходов с элементами управления, связанными с изображениями, поэтому, если у вас есть много неиспользуемых элементов управления, скрытых, но находящихся в памяти, это может быть проблемой.

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

Соедините вещи, о которых следует знать.

1) Для процесса в 32-битной Windows доступно максимум 2 ГБ памяти.Есть способы настроить это на 3 ГБ на машине, но обычно вы не должны ожидать, что будет доступно более 2 ГБ.Ojn Кроме того, обычная фрагментация памяти может привести к тому, что вы получите исключения OutOfMemory, даже если вам кажется, что у вас много свободной памяти.

2) Когда вы имеете дело с коллекциями .NET, обычно они реализуются внутренне.как массивы.Массив - это непрерывный блок памяти.Поэтому, даже если у вас много свободной памяти, можно получить исключение OutOfMemory, потому что нет достаточно непрерывного блока памяти (из-за фрагментации)..NET пытается уменьшить фрейминг, но иногда это похоже на перемещение гигантского стола в переполненной комнате, это не может творить чудеса.

3), поскольку массивы не расширяются динамически, внутренне коллекция должна выделятьновый массив всякий раз, когда ему не хватает места.Обычно это удваивает размер массива каждый раз.Это свойство ".Capacity" большинства коллекций.Вы должны использовать некоторую отладку для мониторинга .Capacity и .Length коллекции.Вы будете наблюдать это удвоение каждый раз, когда коллекция достигает такого размера.Т.е. 128, 256 и т. Д.

Всякий раз, когда он удваивается, он должен выделить новый массив, а затем скопировать содержимое старого массива, прежде чем освободить старый массив.Следовательно, если у вас была коллекция с 256 (или другой степенью 2, например, 64) элементами, а затем добавлен еще один элемент, внутренне коллекция выделяет новый массив из 512 элементов, а затем копирует в него из предыдущего массива.Во время этого переходного процесса у вас есть как 512, так и 256 массивов в памяти.Таким образом, хотя вам нужно только место для 257 элементов, для добавления 257-го элемента требуется в три раза больше места (256 + 512 = 768).

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

Так что, если у вас есть 512 МБ изображений, и коллекция должна быть расширена, чтобы добавить еще один, .NET должен найти пространство для выделения1 ГБ массив изображений.Таким образом, во время этого перехода коллекции, для расширения ее емкости, потребуется 1,5 ГБ ОЗУ.Для .NET будет ОЧЕНЬ ТРУДНО, чтобы найти непрерывный блок 1 ГБ оперативной памяти из-за фрагментации, даже если со всеми шагами .NET, чтобы минимизировать фрагментацию, все еще есть большой контроль.(Кто-то, вероятно, скажет, что массив ссылок намного меньше, но трудно сказать, с чем вы имеете дело.)

Решение: Если вы решите, что это является причиной вашей проблемы, то решение состоит в том, чтобы предсказать, сколько элементов вам потребуется, и заранее установить емкость массива. Поэтому, если у вас есть список изображений, то лучше сначала подсчитать количество этих изображений, а затем установить Емкость коллекции на эту сумму, а может быть, плюс на 10% больше или что-то еще. Таким образом, если у вас есть 300 предметов, вы можете установить емкость на 350. Таким образом, вместо этого вы заранее оценили емкость с небольшим свободным пространством, тогда она никогда не будет расширяться, и, таким образом, не будет испытывать 3-кратный всплеск использование памяти для расширения.

Профилировщики памяти Google .NET. Есть много профилировщиков, а также win debug, которые позволят вам увидеть детали выделения и освобождения памяти, а также фрагментации.

...