Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> ExceptionOutOfMemory, Работа с изображением через GDI32.dll 
:(
    Опции темы
artstalker
Дата 6.2.2010, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 5.2.2009

Репутация: нет
Всего: нет



В программе стоит таймер с интервалом в 100 мс. В обработке таймера захватывается экран монитора и сохраняется в файл. После 5-10 секунд приложение крашится. Приложение сжирает 2 гб ОЗУ и вылетает. Ресурсы вроде бы как освобождаю.
Вот основной класс:
Код

public class Capturing
    {
        Image _bitmap = null;
        ImageFormat _imageFormat = null;

        public void CaptureScreen(ImageFormat imageFormat)
        {
            int hdcSrc = User32.GetWindowDC(User32.GetDesktopWindow()),
            hdcDest = GDI32.CreateCompatibleDC(hdcSrc),
            hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc,
            GDI32.GetDeviceCaps(hdcSrc, 8), GDI32.GetDeviceCaps(hdcSrc, 10)); GDI32.SelectObject(hdcDest, hBitmap);
            GDI32.BitBlt(hdcDest, 0, 0, GDI32.GetDeviceCaps(hdcSrc, 8),
            GDI32.GetDeviceCaps(hdcSrc, 10), hdcSrc, 0, 0, 0x00CC0020);
            _bitmap = TranslateImage(hBitmap, ImageFormat.Jpeg);
            _imageFormat = imageFormat;
            //SaveImageAs(hBitmap, fileName, imageFormat);
            Cleanup(hBitmap, hdcSrc, hdcDest);
        }
        public void SaveImage(string filename)
        {
            if (_bitmap != null)
            {
                _bitmap.Save(filename,_imageFormat);
            }
        }
        private void Cleanup(int hBitmap, int hdcSrc, int hdcDest)
        {
            User32.ReleaseDC(User32.GetDesktopWindow(), hdcSrc);
            GDI32.DeleteDC(hdcDest);
            GDI32.DeleteObject(hBitmap);
        }
        private void SaveImageAs(int hBitmap, string fileName, ImageFormat imageFormat)
        {
            Bitmap image =
            new Bitmap(Image.FromHbitmap(new IntPtr(hBitmap)),
            Image.FromHbitmap(new IntPtr(hBitmap)).Width,
            Image.FromHbitmap(new IntPtr(hBitmap)).Height);
            image.Save(fileName, imageFormat);
            image.Dispose();
            
        }
        private Image TranslateImage(int hBitmap, ImageFormat imageFormat)
        {
            Bitmap image =
            new Bitmap(Image.FromHbitmap(new IntPtr(hBitmap)),
            Image.FromHbitmap(new IntPtr(hBitmap)).Width,
            Image.FromHbitmap(new IntPtr(hBitmap)).Height);
            return image;
        }
    }

Ниже прикрепил проект

Это сообщение отредактировал(а) artstalker - 6.2.2010, 18:45

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  ScreenCapture.rar 394,23 Kb
PM MAIL   Вверх
PashaPash
Дата 7.2.2010, 01:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



artstalker, 
просто ты в диком количестве плодишь объекты Image, и не диспоузишь. 
Код

    public class Capturing
    {
        Image _bitmap = null;
        ImageFormat _imageFormat = null;

        public void CaptureScreen(ImageFormat imageFormat)
        {
            int hdcSrc = User32.GetWindowDC(User32.GetDesktopWindow()),
            hdcDest = GDI32.CreateCompatibleDC(hdcSrc),
            hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc,
            GDI32.GetDeviceCaps(hdcSrc, 8), GDI32.GetDeviceCaps(hdcSrc, 10)); GDI32.SelectObject(hdcDest, hBitmap);
            GDI32.BitBlt(hdcDest, 0, 0, GDI32.GetDeviceCaps(hdcSrc, 8),
            GDI32.GetDeviceCaps(hdcSrc, 10), hdcSrc, 0, 0, 0x00CC0020);

            if (_bitmap != null)
            {
                _bitmap.Dispose();
                _bitmap = null;
            }
            
            _bitmap = TranslateImage(hBitmap, ImageFormat.Jpeg);
            _imageFormat = imageFormat;
            //SaveImageAs(hBitmap, fileName, imageFormat);
            Cleanup(hBitmap, hdcSrc, hdcDest);
        }

        public void SaveImage(string filename)
        {
            if (_bitmap != null)
            {
                _bitmap.Save(filename,_imageFormat);
            }
        }
        private void Cleanup(int hBitmap, int hdcSrc, int hdcDest)
        {
            User32.ReleaseDC(User32.GetDesktopWindow(), hdcSrc);
            GDI32.DeleteDC(hdcDest);
            GDI32.DeleteObject(hBitmap);
        }

        private Image TranslateImage(int hBitmap, ImageFormat imageFormat)
        {
            return Image.FromHbitmap(new IntPtr(hBitmap));
        }
    }

Даже если те 3 лишних, что созданы в TranslateImage умрут быстро, то _bitmap скорее всего проживет дольше, и перепрыгнет во второе поколение. Слей CaptureScreen и SaveFile в одну функцию, сделай _bitmap локальной переменной - будет еще чуть лучше работать. теоретически smile


--------------------
PM MAIL WWW   Вверх
artstalker
Дата 7.2.2010, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 5.2.2009

Репутация: нет
Всего: нет



Цитата(PashaPash @ 7.2.2010,  01:48)
artstalker, 
просто ты в диком количестве плодишь объекты Image, и не диспоузишь. 
Код

    public class Capturing
    {
        Image _bitmap = null;
        ImageFormat _imageFormat = null;

        public void CaptureScreen(ImageFormat imageFormat)
        {
            int hdcSrc = User32.GetWindowDC(User32.GetDesktopWindow()),
            hdcDest = GDI32.CreateCompatibleDC(hdcSrc),
            hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc,
            GDI32.GetDeviceCaps(hdcSrc, 8), GDI32.GetDeviceCaps(hdcSrc, 10)); GDI32.SelectObject(hdcDest, hBitmap);
            GDI32.BitBlt(hdcDest, 0, 0, GDI32.GetDeviceCaps(hdcSrc, 8),
            GDI32.GetDeviceCaps(hdcSrc, 10), hdcSrc, 0, 0, 0x00CC0020);

            if (_bitmap != null)
            {
                _bitmap.Dispose();
                _bitmap = null;
            }
            
            _bitmap = TranslateImage(hBitmap, ImageFormat.Jpeg);
            _imageFormat = imageFormat;
            //SaveImageAs(hBitmap, fileName, imageFormat);
            Cleanup(hBitmap, hdcSrc, hdcDest);
        }

        public void SaveImage(string filename)
        {
            if (_bitmap != null)
            {
                _bitmap.Save(filename,_imageFormat);
            }
        }
        private void Cleanup(int hBitmap, int hdcSrc, int hdcDest)
        {
            User32.ReleaseDC(User32.GetDesktopWindow(), hdcSrc);
            GDI32.DeleteDC(hdcDest);
            GDI32.DeleteObject(hBitmap);
        }

        private Image TranslateImage(int hBitmap, ImageFormat imageFormat)
        {
            return Image.FromHbitmap(new IntPtr(hBitmap));
        }
    }

Даже если те 3 лишних, что созданы в TranslateImage умрут быстро, то _bitmap скорее всего проживет дольше, и перепрыгнет во второе поколение. Слей CaptureScreen и SaveFile в одну функцию, сделай _bitmap локальной переменной - будет еще чуть лучше работать. теоретически smile

Я пробовал диспозить. И даже пробовал вручную заставлять GC собирать мусор после каждого сохранения. Результат один и тот же...
PM MAIL   Вверх
PashaPash
Дата 7.2.2010, 14:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



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

А вручную собирать мусор нельзя. точнее, можно, но только если точно знаешь как работает GC.

Это сообщение отредактировал(а) PashaPash - 7.2.2010, 14:52


--------------------
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1414 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.