.NET Framework Developer Center > .NET Development Forums > Windows Presentation Foundation (WPF) > OutOfMemoryException when retrieving a bitmap from an IDataObject
Ask a questionAsk a question
 

QuestionOutOfMemoryException when retrieving a bitmap from an IDataObject

  • Tuesday, September 09, 2008 8:14 PMThe_Bell Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Hi,

    I'm having a strange exception, and I hope you can help me debug it.

    I'm using the IDataObject interface returned from the Clipboard.GetDataObject() method to access the object currently on the System Clipboard.

    The problem is that when the object on the DataObject class is a bitmap, I get an OutOfMemoryException when retrieving the data numerous times, even when the available memory on the system is huge (and the program itself is not consuming too much memory considering the size of the images.

    I get the exception on the IDataObject.GetData(DataFormats.Bitmap) method. Here's the stacktrace:

       at System.Runtime.InteropServices.ComTypes.IDataObject.GetData(FORMATETC& format, STGMEDIUM& medium)
       at System.Windows.DataObject.OleConverter.GetDataInner(FORMATETC& formatetc, STGMEDIUM& medium)
       at System.Windows.DataObject.OleConverter.GetDataFromOleOther(String format, DVASPECT aspect, Int32 index)
       at System.Windows.DataObject.OleConverter.GetDataFromBoundOleDataObject(String format, DVASPECT aspect, Int32 index)
       at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert, DVASPECT aspect, Int32 index)
       at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert)
       at System.Windows.DataObject.GetData(String format, Boolean autoConvert)
       at System.Windows.DataObject.GetData(String format)
       at DataTest.Window1.Button_Click(Object sender, RoutedEventArgs e) in C:\sourcesbernat\DataTest\DataTest\Window1.xaml.cs:line 35

    You can test the problem using this sample application. Copy a string on the clipboard and click on the button, then "print screen" and click again to see the different behaviour depending on the type of the object stored.

    Here's the XAML of the window:
    <window x:class="DataTest.Window1" xmlns:x="#unknown"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
          Title="Window1" Height="300" Width="300"&gt; 
          <stackpanel> 
                <button click="Button_Click">Click Me!</button> 
                <image x:name="ImageThumb"></image> 
          </stackpanel> 
    </window> 

    And here is the code behind file:
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Data; 
    using System.Windows.Documents; 
    using System.Windows.Input; 
    using System.Windows.Media; 
    using System.Windows.Media.Imaging; 
    using System.Windows.Navigation; 
    using System.Windows.Shapes; 
     
    namespace DataTest 
          /// <summary> 
          /// Interaction logic for Window1.xaml 
          /// </summary> 
          public partial class Window1 : Window 
          { 
                public Window1() 
                { 
                      InitializeComponent(); 
                } 
     
                private void Button_Click(object sender, RoutedEventArgs e) 
                { 
                      for (int i = 0; i &lt; 100; i++) 
                      { 
                            IDataObject dataObject = Clipboard.GetDataObject(); 
                            
                         if (dataObject.GetDataPresent(DataFormats.Bitmap)) 
                            { 
                                  ImageThumb.Source = (BitmapSource)dataObject.GetData(DataFormats.Bitmap); 
                            } 
                         else if (dataObject.GetDataPresent(DataFormats.Text)) 
                         { 
                               string s = (string)dataObject.GetData(DataFormats.Text); 
                         } 
                      } 
                } 
          } 

    I know the code is stupid, but it's just to reproduce the problem. In my app it just happens randomly when retrieving data from the dataobjects.

    You can test the problem using this sample application. Copy a string on the clipboard and click on the button, then "print screen" and click again to see the different behaviour depending on the type of the object stored.

    Thanks!


    • Moved bynobugzMVP, ModeratorWednesday, September 10, 2008 5:09 AMNot BCL (Moved from .NET Base Class Library to Windows Presentation Foundation (WPF))
    • Changed TypeMarco Zhou Tuesday, September 16, 2008 9:43 AMOP doesn't revert back
    • Changed TypeThe_Bell Wednesday, September 17, 2008 8:15 AMAnswered the questions of the moderator
    •  

All Replies

  • Friday, September 12, 2008 6:51 AMMarco Zhou Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I expect each call to GetData(DataFormats.Bitmap) will generate a separate BitmapSource instance which could easily drain the memory if you call it hundreds or even thousands of times, what's your usage scenario?

    Thanks
  • Tuesday, September 16, 2008 9:43 AMMarco Zhou Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    We are changing the issue type to “Comment” because you have not followed up with the necessary information. If you have more time to look at the issue and provide more information, please feel free to change the issue type back to “Question” by clicking the "Options" link at the top of your post, and selecting "Change Type" menu item from the pop menu. If the issue is resolved, we will appreciate it if you can share the solution so that the answer can be found and used by other community members having similar questions.

     

    Thank you!

  • Wednesday, September 17, 2008 8:14 AMThe_Bell Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi,

    Excuse me for not answering, I was not alerted by email of your responses.

    My usage scenario is simple: every time the user copies an image to the clipboard I store that IDataObject in memory (top 10 copies, not more).

    Then those IDataObjects are databound to a listbox, where they are rendered as an image using a ValueConverted derived class which actually performs that operation on the IDataObject of the collection, and returns an Image WPF contol so the engine can render it as a ListBoxItem.

    This usually happens with big images (such as a full desktop screenshot), but if I can't guarantee I'll be able to render at least those 10 bitmaps in the listbox (thumbnailed of course), the project will be pointless. In my case, trying to load like 7 images of my desktop throws the error (1280x1024 desktop res).

    About the memory usage, I expect the BitmapSource to be freed when every loop ends. As it is a local variable to the loop, before getting an outofmemory exception, the system should try to free the previous unused bitmapsources? I also don't know how exactly the IValueConverter calls work behind the scenes when you're databinding, but I guess there will be something similar to a loop there, too, for each of the ObservableCollection items.

    If you need any more information, let me know.
    • Edited byThe_Bell Wednesday, September 17, 2008 1:34 PM
    •  
  • Thursday, September 18, 2008 4:07 AMMarco Zhou Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    -> About the memory usage, I expect the BitmapSource to be freed when every loop ends. As it is a local variable to the loop, before getting an outofmemory exception, the system should try to free the previous unused bitmapsources? I also don't know how exactly the IValueConverter calls work behind the scenes when you're databinding, but I guess there will be something similar to a loop there, too, for each of the ObservableCollection items.

    But you are allocating quite large bitmap aka 1280x1024 resolution, if the color depth is 24 bits, it will be 1280x1024x24x500 = 1.92 GB, given that user mode programmes only have nearly 2 GB virtual address to manipulate with, and since GC will deallocate resources in indeterministic fashion, you could easily run out of virtual address space.

    Hope this clears things up a little bit.
  • Thursday, September 18, 2008 7:09 AMThe_Bell Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Where does the last 500 of the formula come from?
  • Friday, September 19, 2008 6:34 AMMarco Zhou Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    -> Where does the last 500 of the formula come from?

    Oops, it should be 100, since in your original code, you loop for 100th times:)

    Anyway, I think the same idea still holds true, in particular, when you need to create such as large bitmap in the tight loop?

    Thanks
  • Friday, September 19, 2008 7:26 AMThe_Bell Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi,

    I don't really need to do a 100 iteration loop. This code was only to reproduce the problem. The loop occurs internally when I convert a IDataObject collection I have to the corresponding thumbnails to be shown in a ListBox (via DataBinding the collection to the listbox and having a value converter to do the job of converting the IDataObjects to the Image control).

    The OutOfMemoryException occurs when having about 7 screenshots of the desktop. I guess I'll have to find a way to store that data in temporary files so it's evident I can't hold all that information in memory.

    Thanks!
  • Wednesday, November 04, 2009 11:15 PMtilovell Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I've hit this same OutOfMemoryException, same call stack

    at System.Runtime.InteropServices.ComTypes.IDataObject.GetData(FORMATETC& format, STGMEDIUM& medium)
       at System.Windows.DataObject.OleConverter.GetDataInner(FORMATETC& formatetc, STGMEDIUM& medium)
       at System.Windows.DataObject.OleConverter.GetDataFromOleHGLOBAL(String format, DVASPECT aspect, Int32 index)
       at System.Windows.DataObject.OleConverter.GetDataFromBoundOleDataObject(String format, DVASPECT aspect, Int32 index)
       at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert, DVASPECT aspect, Int32 index)
       at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert)
       at System.Windows.DataObject.GetData(String format, Boolean autoConvert)
       at System.Windows.DataObject.GetData(String format)


    by using the context menu in Visual Studio 10 beta 2 on Win2k8. I have no idea what was on the clipboard at the time. I'm pretty sure I wasn't in some extreme memory usage situation.