2015-07-24 4 views
1

Я хочу показать Bitmap в контейнере Image с WPF.Растровая графика CreateBitmapSourceFromHBitmap утечка памяти

private void updateImagePreview() 
{ 
    Bitmap bmp = new Bitmap(Screen.PrimaryScreen.WorkingArea.Width, 
          Screen.PrimaryScreen.WorkingArea.Height); 
    Graphics gr = Graphics.FromImage(bmp); 
    Image Image_Preview; 

    while (true) 
    { 
     gr.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(bmp.Width, bmp.Height)); 
     Image_Preview.Source = loadBitmap(bmp); 
    } 
} 

[DllImport("gdi32")] 
static extern int DeleteObject(IntPtr o); 
public BitmapSource loadBitmap(System.Drawing.Bitmap source) 
{ 
    IntPtr ip = source.GetHbitmap(); 
    BitmapSource bs = null; 
    try 
    { 
     bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
       ip, IntPtr.Zero, Int32Rect.Empty, 
       System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); 
    } 
    finally 
    { 
     DeleteObject(ip); 
    } 

    return bs; 
} 

Проблема в том, что это создает огромную утечку памяти. Утечка происходит по вызову CreateBitmapSourceFromHBitmap и заполняет память при циклическом перемещении до превышения предела. Если я не использую этот вызов, утечка исчезнет. Любая идея, почему это происходит?

+0

Что вы имеете в виду под «утечкой памяти»? Он хранит ссылки в памяти после того, как он должен был быть уничтожен? Или один вызов заполняет вашу память? – almulo

+0

Он держит ссылки. Один вызов будет работать, но утечка памяти все равно будет. – Flupp

+0

Вы видели [этот точно такой же вопрос] (http://stackoverflow.com/q/28952654/1136211)? У него много ссылок, но ответа нет. – Clemens

ответ

0

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

Timer takeScreen; 

// This is a button to start the screen capturing 
private void Button_Play_Click(object sender, RoutedEventArgs e) 
    { 
     int fps = 30; 
     takeScreen = new Timer(o => addNewImage(), null, 0, 1000/fps); 
    } 

private void addNewImage() 
    { 
     using (Bitmap bmp = new Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height)) 
     { 
      using (Graphics gr = Graphics.FromImage(bmp)) 
      { 
       gr.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(bmp.Width, bmp.Height)); 
       Image_Preview.Dispatcher.Invoke(new Action(() => Image_Preview.Source = loadBitmap(bmp))); 
      } 
     } 
    } 

public BitmapSource loadBitmap(System.Drawing.Bitmap source) 
    { 
     BitmapSource bmpf = null; 

     using (MemoryStream ms = new MemoryStream()) 
     { 
      using (WrappingStream ws = new WrappingStream(ms)) 
      { 
       source.Save(ws, System.Drawing.Imaging.ImageFormat.Bmp); 
       bmpf = BitmapFrame.Create(ws, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); 
      } 
     } 

     return bmpf; 
    } 
0

Попробуйте позвонить Freeze() на свой BitmapSource, прежде чем возвращать его. Кажется, это помогает освободить некоторые ссылки на байты изображения.

[DllImport("gdi32")] 
static extern int DeleteObject(IntPtr o); 
public BitmapSource loadBitmap(System.Drawing.Bitmap source) 
{ 
    IntPtr ip = source.GetHbitmap(); 
    BitmapSource bs = null; 
    try 
    { 
     bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
       ip, IntPtr.Zero, Int32Rect.Empty, 
       System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); 
    } 
    finally 
    { 
     DeleteObject(ip); 
    } 

    bs.Freeze(); 
    return bs; 
} 
+0

Я пробовал, но не помог. – Flupp

0

Если у вас есть утечка памяти, то первое, что вы должны проверить это, если есть какие-то одноразовые предметы, которые не расположены.

Я вижу, что вы не располагаете экземплярами Image и Graphics, что может привести к утечкам памяти.

Убедитесь, что вы располагаете их в конце их использования.

Например: В updateImagePreview методы

using (Graphics gr = Graphics.FromImage(bmp)) 
{ 
    .... 
} 

Например: В loadBitmap методы

public BitmapSource loadBitmap(System.Drawing.Bitmap source) 
{ 
    .... 

    finally 
    { 
     DeleteObject(ip); 
     source.Dispose(); 
    } 

    return bs; 
} 
Смежные вопросы