Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > ExceptionOutOfMemory


Автор: artstalker 6.2.2010, 18:44
В программе стоит таймер с интервалом в 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;
        }
    }

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

Автор: 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

Автор: artstalker 7.2.2010, 13:37
Цитата(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 собирать мусор после каждого сохранения. Результат один и тот же...

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

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)