System: Windows XP SP3, .NET 3.5, 4GB RAM, Dual 1.6gHz
I have a WPF application that loads and transitions (using Storyboard animations) extremely large PNGs. These PNGs are 8190x1080 in resolution. As the application runs it appears to cache the images and the system Memory slowly creeps up. Eventually it chokes the system and throws the OutOfMemoryException.
Here are the steps I am currently taking to try to solve this:
1)I am removing the BitmapSource objects from the app
2)I am setting the BitmapSource BitmapCacheOption to None when I load the BitmapSource
3)I am Freezing the BitmapSource once it's loaded.
4)I am deleting all references to the Image that uses the source as well as any references to the source itself.
5)Manually calling GC.Collect() after above steps have completed.
Hoping to figure out why WPF is hanging onto memory for these images and a possible solution to ensure that the memory used to load them is properly recovered.
You certainly have put in a lot of work on this. I think the main problem is that BitmapCacheOption.None doesn't prevent the underlying BitmapDecoder(s) from being cached.
There are several tricky solutions to this such as doing a GC.Collect(), loading 300 small images from 300 different Uris, and calling GC.Collect() again, but the simple one is straightforward:
Instead of loading from a Uri, just construct a Stream and pass it to BitmapFrame's constructor:
var source = new BitmapImage();
using(Stream stream = ...)
{
source.BeginInit();
source.StreamSource = stream;
source.CacheOption = BitmapCacheOption.OnLoad; // not a mistake - see below
source.EndInit();
}
The reason this should work is that loading from a stream completely disables the cache. Not only is the top-level source not cached, but none of the internal decoders are cached either.
Why BitmapCacheOption.OnLoad? It seems counterintuitive, but this flag has two effects: It enables caching if caching is possible, and it causes the load to happen at EndInit(). In our case caching is impossible, so all it does it cause the load to happen immediately.
Obviously you'll want to run this code off your UI thread, then freeze the BitmapSource so you can move it over.
You may also wonder why I didn't use BitmapCreateOptions.IgnoreImageCache. Other than the fact that caching is impossible any with no URI given, the IgnoreImageCache doesn't completely ignore the image cache: It only ignores it for reading. So even if IgnoreImageCache is set, the loaded image is still inserted into the cache. The difference is that the existing image in the cache is ignored.
Related
I have a x86 application working on windows10 (64 bit environment).
One pf the app's features is to generate a lot of reports, so there is a lot of printing involved.
However, I noticed that every time I try to use call DefaultPrintTicket on the print queue the dllhost process (COM Surrogate) grows in memory.
I managed to isolate the code responsible and moved it to a test WPF app. When a button is clicked this code is being fired:
var localPrintServer = new LocalPrintServer();
var oneNotePrintQueue = localPrintServer.GetPrintQueues().FirstOrDefault(p => p.Description.Contains(OneNote));
var printTicket = oneNotePrintQueue?.DefaultPrintTicket;
The printing queue is irrelevant as I tried them all and the problem remains.
I am aware that this might be a duplicate to: PrintTicket DllHost.exe Memory Climbs
However, the solution provided there does not work as PrintTicked is not an IDisposable object.
I also tried some tweaks in the registry (i.e. finding AppId AA0B85DA-FDDF-4272-8D1D-FF9B966D75B0 and removing "AccessPermission", "LaunchPermission" and "RunAs") with no result.
I cannot rebuild the app as AnyCpu and I would like to avoid creating a separate 64bit process just for printing as it would be difficult to send a report generated in one app to another.
Any suggestions are greatly appreciated.
It seems that the topic is difficult.
Just want to share the solution I went with in case anyone else has the same problem.
In the end I created a separate x64 app which handles the printing.
Initially I wanted to go with a WCF service. However, I ran into problems with serializing of FixedDocuments and PrintQueue. Hence the separate app.
The solution if far from perfect and in my opinion is not nice at all. However, it solved the memory leak issue.
This question refers to Codename One only.
I have a Form with a Tabs and each tab can contain an arbitrary number of images (taken from the Gallery).
Result: after few images (eight images from the gallery), on my Android device I get:
java.lang.OutOfMemoryError: Failed to allocate a 5683356 byte allocation with 1845080 free bytes and 1801KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:737)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:703)
at com.codename1.impl.android.c.b(AndroidImplementation.java:2037)
at com.codename1.r.z.a(Image.java:531)
at cool.teammate.apps.frontend.b.e.a$1.a(BasePageForm.java:208)
at com.codename1.r.l.b.a(EventDispatcher.java:349)
at com.codename1.impl.android.c.a(AndroidImplementation.java:7336)
at com.codename1.impl.android.CodenameOneActivity$6.run(CodenameOneActivity.java:527)
at com.codename1.r.r.n(Display.java:1298)
at com.codename1.r.r.l(Display.java:1242)
at com.codename1.r.r.k(Display.java:1130)
at com.codename1.r.aq.run(RunnableWrapper.java:120)
at com.codename1.impl.b$1.run(CodenameOneThread.java:60)
at java.lang.Thread.run(Thread.java:776)
Also iOS crashes, but I haven't the log.
Each image is scaled before showing (using the class FixedSizeButton, that I reported in this question). Any suggestion?
I guess that the dispose() method of Image can be useful, but it's written to "DO NOT CALL THIS METHOD UNLESS YOU KNOW WHAT YOU ARE DOING". Is it so problematic? For example, can it help if I dispose an Image after saving it to file and/or after scaling?
I also guess that System.gc() can be useful.
However, if few photos are so problematic... how can I make a photo gallery inside a Form without this kind of issues? Same problem to load hundreds of photo post inside an InfiniteContainer...
Note that the memory issue happens regardless if I insert the images as icon of a Button or as filled background of the Button.
Thank you for your suggestion.
You don't need to call dispose() or gc() for a proper application. You're trying to load a 5mb image which I'm assuming is a 5mb JPEG. That's probably from a 9+ mega pixel camera which means the decompressed size would be roughly 9 x 4 == 36MB!
So 36 x 8 = 288mb of RAM.
this.image = Image.createImage(this.imageWidth, this.imageHeight, 0xFFdddddd);
What's imageWidth/Height?
You might be taking a lot of RAM here...
this.setIcon(this.image);
EasyThread scalingThread = EasyThread.start("FixedSizeButton-ScalingImg-" + fileName);
Since you're creating multiple threads you might have all 8 images in RAM at once.
A better way is to use one image scaling thread. An even better approach is avoiding scaled altogether and using ImageIO to scale the image without loading it into RAM.
On certain computers I have a WPF application that doesn't release memory when working with it. For instance when sending a document to the printer, on most computers it's releasing memory all the 2-3 seconds (it's going up for maybe 200 megs then coming back down), which is normal behaviour and when the printing is done I go back to my initial memory state.
But on some computers (over 20 computers installed and only one is giving me this issue) it's not freeing the memory. It keeps piling up. I don't mind seeing memory going to 1.5 Gb as long as it's releasing it in the end, but it's not and I get an OutOfMemoryException.
I don't have full access to the problematic computer (they're a client's computer we installed a week ago and we just saw this problem) so I can't really test it but it's a standard Windows 7 Pro x64, with 10Gb of RAM and aside from that, it's working like a charm.
Also it's not ONLY when printing. The application is kind of a PDF viewer and everytime a new page is loaded for the user, the previous page is freed from memory. Again, it's working fine on most PC, but not in these case.
Is there anything that could prevent the memory from being released? I can't seem to find a similar problem anywhere on the web.
EDIT: Okay I got a hold of the computer for an hour. I was able to test two things :
GC.Collect() didn't arrange anything (I even forced it with GC.WaitForPendingFinalizer)
I tried disposing of the DocumentPage in my Paginator, no luck. I also kept a reference of a ViewModel I was using to display my page on printing, I tried disposing it : didn't work.
What I can say is that in both cases it must be because of the images displayed in my pages. Here's the function I call to get a new page image :
'First I get the path to the images
Dim path As String = String.Format("{0}\{1}.png", Me.TemporaryFolderPath, page.PageId)
Dim imgSource As CachedBitmap
'If the file doesn't exist
If Not IO.File.Exists(path) Then
'A function is called which creates the png file for next uses (this way the first loading is slow, but the next times it's faster)
imgSource = Pdf.GetPageImage(page.PageNumber, path)
Else
'If the file exists I instantiate a new BitmapImage
Dim img As New BitmapImage
'And I load it in a stream
Using stream As IO.FileStream = IO.File.OpenRead(path)
'I apply the stream to my image
img.BeginInit()
img.CacheOption = BitmapCacheOption.OnLoad
img.StreamSource = stream
img.EndInit()
'Flush, close, dispose of my stream
stream.Flush()
stream.Close()
End Using
'And I create a CachedBitmap with this image (which is almost like an ImageSource)
imgSource = New CachedBitmap(img, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
img = Nothing
End If
'If my ImageSource is something, I freeze it so that the memory is freed afterwards
If imgSource IsNot Nothing Then imgSource.Freeze()
Return imgSource
All this (freezing the image, setting the cacheOption to OnLoad, loading from a stream) I did to avoid memory leaks. My first attempt to load an image has a huge leak and I refactored my function so that I didn't have this problem anymore.
Is there anything there that could be the problem?
Finally my problem was that I was keeping my current page image in a ReadOnly Property. Even though I was disposing the image (the local variable used by the ReadOnly Property) it wasn't releasing it.
Maybe because of the OnPropertyChanged implemented on my ViewModels, because when I made it a read/write property and I disposed of it and set it to null on every change of page, it was releasing the memory on the problematic computers.
I have an app which plays a few short sound clips. To play them I simply set the source to the new clip path, which is a WMA I encoded with Expression Encoder using WP7 settings. It's not even worth sharing the code -- there's an event handler. In it, I set the ME.Source property to a new Uri. It's set to AutoPlay, so that's it! Here:
private void PlaySound(ItemViewModel sound) {
Model.CurrentSound = sound;
CurrentSound.Source = new Uri(sound.Path, UriKind.Relative);
}
private void Sounds_SelectionChanged(object sender, SelectionChangedEventArgs e) {
var list = ((ListBox) sender);
var item = (ItemViewModel) list.SelectedItem;
SelectItem(item);
}
Also I should point out that the sounds are all resources (build type = Resource). I need them to be because the app needs to discover them dynamically. The paths are all like this, "sounds/foo/bar/sound.wma". Sometimes there is a space in the path, it is url encoded with %20 (this is how the resource manager returns the path, I didn't do that).
The problem is many people, but not all, are saying that the sound auto-repeats. The sounds are very short, only a few seconds, so it's very annoying. I don't understand how this is happening, the MediaElement doesn't even have an auto repeat feature.
Perhaps related, but some have also complained that every now and then the sound does not play. They have to click it again. All I can think of is that there is something wrong with how the sounds are encoded, but they are WMA, and as I said, I encoded them using the 'playback in WP7' settings in expression encoder. How could it be that it works usually but not other times if that were the case, anyway?
I'm at a loss and my app is getting some bad reviews because of this behavior. Help!
"there's and event handler" but you don't say of what? It could be that event firing over and over or not at all in some cases. Potentially your code has a logical errors where you have failed to detach an existing handler and then added another. As usage progresses you end up with a single event being handled by multiple handlers.
Edit
The Selection changed event is notorious for firing more frequently than we'd like. I suggest you add some debounce code that makes record of the last item selected and how long ago. If the next selected item is the same as the last one and it was say less than a second ago then swallow the event without doing anything else.
It sounds like you might be trying to play Sound Effects - in which case you might be better off using the XNA SoundEffect mechanism
e.g. http://www.japf.fr/2010/08/sound-effect-in-wp7-sl-application/
SoundEffect only works for WAV files (PCM) - but I've used it in several apps and scripts including embedded content files and downloaded files (e.g. translation and ironruby scripts).
The XNA class works well within SL and allows multiple sound effects to be played at the same time.
The problem with repeating turned out to be needing to do this:
MediaPlayer.IsRepeating = false;
I think what happened was the user would be in another app that sets this to true, and upon opening my app that value was still true! That has to be a bug, it's totally unexpected. If you look at other sound-playing apps like soundboard apps, there are users complaining in the reviews about the very same thing.. "I wish it wouldn't repeat the sounds..."
I'm currently developing a WPF application where one of the controls displays a stream of images; much like any webcam. These images originate of an IP camera and can only be accessed by an HTTP Url, which is fixed and always the sames. Now capturing the images is no problem, via
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = uri;
bitmapImage.CacheOption = BitmapCacheOption.None;
bitmapImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
bitmapImage.EndInit();
return bitmapImage;
This much works. The problem arises when I attempt to hook up several cameras (more than 6), the application chokes and eventually crashes. All cameras run on a separate thread btw.
I've identified the basic problem: creating a (highlevel?) bitmap eats too much resources as I need the app to process about 600 images/sec in real-time (about 30Mb/sec) eventually.
In a nutshell, i'm looking for a way to make this retrieval/rendering process a lot more efficient.
Thanks in advance!
UPDATE:
Forgot to mention perhaps, im working in .NET 4 WPF, the camera itself is a Mobotix M12, accessed by ethernet.
So, if I get this right, each camera has a framerate of 100 fps? (you mention 600 images/second for 6 cams).
With some profiling you could identify the bottleneck?
As a very late update and for anyone still interested - we managed an implementation with the aForge framework http://www.aforgenet.com/aforge/framework
While dated, it can do these kind of things out of the box.