Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Загрузка картинок и освобождение памяти

1
03 декабря 2008 года
kot_
7.3K / / 20.01.2000
Целевая система: Windows Mobile 5.0
Не могу понять в чем проблема - следующий код работает нормально, до определенного момента, затем генерирует исключение нехватки памяти (OutOfMemoryException). Исключение перехватывается - а как память вернуть системе? Или по крайней мере позволить приложению с ней работать?
Код:
if (odMain.ShowDialog()== DialogResult.OK) {
                try
                {
                    Bitmap tmpBitmap = new Bitmap(odMain.FileName);
                    pbMain.SizeMode = PictureBoxSizeMode.StretchImage;
                    pbMain.Image = (Image)tmpBitmap;
                    lbMain.Visible = false;
                }
                catch (OutOfMemoryException ex) {
                    ?????//Как получить память обратно здесь?
                    return;
                }
            }

        }
    }
1
03 декабря 2008 года
kot_
7.3K / / 20.01.2000
В данном случае решение следующее - объявляем закрытую статическую переменную класса формы и перед выделением ресурсов освобождаем предыдущее.
Т.е.
Код:
public partial class fmMain : Form
{
        private static Bitmap tmpBitmap;
       
...

        private void pbMain_Click(object sender, EventArgs e)
        {
           
            if (odMain.ShowDialog()== DialogResult.OK) {
                try
                {
                    if (tmpBitmap!=null) { tmpBitmap.Dispose(); tmpBitmap = null; }
                    tmpBitmap = new Bitmap(odMain.FileName);
                                     pbMain.SizeMode = PictureBoxSizeMode.StretchImage;
                        pbMain.Image = (Image)tmpBitmap;
                       
                        lbMain.Visible = false;
                   
                   
                }
                catch (OutOfMemoryException ex)
                {
                          return;
                }

               
            }

        }

    ...
 }

ну и естественно надо делать освобождение ресурса там где он уже не нужен.
8.2K
03 декабря 2008 года
bagie2
299 / / 26.10.2008
Вопрос. Зачем создавать объект Bitmap?

а если так?
 
Код:
...
pbMain.SizeMode = PictureBoxSizeMode.StretchImage;
pbMain.Load(odMain.FileName);
...
1
03 декабря 2008 года
kot_
7.3K / / 20.01.2000
Цитата: bagie2
Вопрос. Зачем создавать объект Bitmap?

а если так?
 
Код:
...
pbMain.SizeMode = PictureBoxSizeMode.StretchImage;
pbMain.Load(odMain.FileName);
...


хм. Ну для создания отдельного объекта есть свои причины - а вот откуда у компонента PictureBox взялся этот метод?

8.2K
03 декабря 2008 года
bagie2
299 / / 26.10.2008
kot_
http://msdn.microsoft.com/en-us/library/f6ak7was.aspx

кстати тогда может быть так сделать, если нужно еще как-то обрабатывать изоражение перед загрузкой?

Код:
if (odMain.ShowDialog() == DialogResult.OK)
            {
                Bitmap tmpBitmap = new Bitmap(odMain.FileName);
   
                //... тут еще что-то делаем с битмапом
 
                pbMain.SizeMode = PictureBoxSizeMode.StretchImage;

                try { pbMain.Image.Dispose(); }
                catch { }

                pbMain.Image = tmpBitmap;            
            }
341
03 декабря 2008 года
Der Meister
874 / / 21.12.2007
[QUOTE=kot_]хм. Ну для создания отдельного объекта есть свои причины - а вот откуда у компонента PictureBox взялся этот метод?[/QUOTE]Есть, есть такой в принципе, но, к сожалению, нету его в Compact Framework.
А вообще странно... Неуправляемый ресурс должен освобождаться как минимум при сборке мусора, а в случае, когда память на исходе, сборщик мусора по-любому должен сработать. Т. е. твое решение, в принципе, должно быть эквивалентно вот такому:
 
Код:
pictureBox.Image = null;
Bitmap bitmap = new Bitmap(path);
pictureBox.Image = bitmap;

Но другое странно: как это памяти остаётся меньше чем на картинку?
1
03 декабря 2008 года
kot_
7.3K / / 20.01.2000


не поддерживается. Я указал целевую платформу.

Цитата: bagie2
kot_
кстати тогда может быть так сделать, если нужно еще как-то обрабатывать изоражение перед загрузкой?


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

Цитата:

Но другое странно: как это памяти остаётся меньше чем на картинку?


Данное исключение генерируется при невозможности выделить память одним фрагментом - т.е. память на самом деле есть - просто нет возможности в данный текущий момент выделить именно столько непрерывной памяти. Т.е. если я допустим получил исключение - а затем загрузил картинку меньшего размера - то я смогу затем загрузить и нужную мне картинку. Т.е. "сборщик мусора" отрабатывает и дефрагментация памяти происходит. Просто я не могу управлять этим процессом - вот в чем вопрос :) Возможно в C# это просто не возможно сделать - хз. я еще не разобрался.

1
03 декабря 2008 года
kot_
7.3K / / 20.01.2000
Ради интереса провел эксперимент. Добавил две кнопки, функция на одной использует статическую переменную и чистит указатель, вторая просто создает объект и обрабатывает исключения. При этом объем памяти, которая может быть выделена фиксируется. Так как мне нужно получать текущее состояние памяти - я установил параметр в false - так помоему ближе к реальной ситуации.
Код 1:
Код:
private void pbMain_Click(object sender, EventArgs e)
        {
            lbList.Items.Add("Memory 1" + GC.GetTotalMemory(false).ToString());
            if (odMain.ShowDialog()== DialogResult.OK) {
                   if (tmpBitmap!=null) { tmpBitmap.Dispose(); tmpBitmap = null; }
                   try
                   {
                       tmpBitmap = new Bitmap(odMain.FileName);
                       pbMain.SizeMode = PictureBoxSizeMode.StretchImage;
                       pbMain.Image = (Image)tmpBitmap;
                       lbMain.Visible = false;
                   }
                   catch (OutOfMemoryException ex)
                   {
                       System.GC.Collect();
                       return;
                   }
                   finally {
                       lbList.Items.Add("Memory 1 " + GC.GetTotalMemory(false).ToString());
                   }
            }
 }

Код 2:
Код:
private void bbBad_Click(object sender, EventArgs e)
        {
            lbList.Items.Add("Memory 2" + GC.GetTotalMemory(false).ToString());
            if (odMain.ShowDialog() == DialogResult.OK)
            {
                try
                {
                   Bitmap tmpBitmap2 = new Bitmap(odMain.FileName);
                    pbMain.SizeMode = PictureBoxSizeMode.StretchImage;
                    pbMain.Image = (Image)tmpBitmap2;
                    lbMain.Visible = false;
                }
                catch (OutOfMemoryException ex)
                {
                    System.GC.Collect();
                    return;
                }
                finally {
                    lbList.Items.Add("Memory 2" + GC.GetTotalMemory(false).ToString());
                }
            }
        }

Результат работы первого кода:
Цитата:

Memory1 6388
Memory1 537668
Memory1 539278
Memory1 529689
Memory1 532710
Memory1 596809
....


результат работы второго:

Цитата:

Memory2 599020
Memory2 538084
Memory2 538512
Memory2 7048
Memory2 7468
Memory2 7160
<<<<<<<<<<<На следующем шаге уже возникло исключение
Memory2 7580
Memory2 7272
Memory2 7580 << Опять пытаюсь открыть - и опять исключение
Memory2 7272
<<<<<<<< А вот здесь открыта маленькая картинка, для нее памяти хватило
Memory2 7804
Memory2 402988
....

1
03 декабря 2008 года
kot_
7.3K / / 20.01.2000
почему нормально не отрабатывает "сборщик мусора"?
На самом деле он нормально работает - и работает именно так как надо.
Дело в том что в первом коде память возвращается в систему, потому что переменная объявлена за пределами функции - мы имеем возможность "обнулить" указатель, и перед вызовом функции new происходит очистка памяти.
Почему же во втором случае не так? Да элементарно. Объект который, как мы считаем должен быть очищен, на самом деле не подпадает под критерии очистки! На него есть как минимум одна ссылка - на него ссылается поле класса PaintBox! И поэтому память не возвращается в систему. А когда нормально произошел вызов функции new - то тогда (и только тогда) предыдущая картинка становится мусором - ведь Image уже указывает на другой объект. Поэтому в данном случае предпочтительнее объявить указатель за пределами функции - или пытаться освободить объект через Image (я так думаю что это должно сработать - хотите попробуйте)
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог