My CF application has a very customized UI, using lots of images as UI elements. The UI feels a lot more smooth when these bitmaps are kept in memory. When they're loaded on demand, the UI is slow and I can see the buttons appearing one by one, which looks very poor. For a long time this went pretty well, but recently I've found the application nearly uses all the memory it can get, which is 32MB iirc. I then started using the remote performance monitor to see if I could find any clear memory hogs.
As it turns out, getting a useful snapshot of the GC heap using RPM is hard: close before I'm likely to receive out of memory exceptions, requesting a snapshot causes a native exception to be thrown instantly. I can manage to find a GC snapshot once in a while though. I saved one here: http://files.zzattack.org/misc/ramis.gclog and a screenshot here: http://files.zzattack.org/images/ramisgcsnapshot.png To me it doesn't look all that troublesome, by far the largest object is a byte array containing my resources file (about 3MB full of PNG images). Alltogeher, 3643304b (about 3.5MB) of memory is used. These images are spread ov开发者_运维技巧er UI elements in about 20 different forms. I'm don't know what impact seperate threads have on memory usage, but about 5-6 threads are running simultaneously, of which at least 4 are in a blocked state 95% of the time.
In the program, when I attempt to download a 2MB gzipped file, I will always receive an OutOfMemoryException. When I call GC.GetTotalMemory(false), I see that I am indeed attempting to allocate more than is currently available. Calling GC.Collect and trying again doesn't 'solve'/postpone my problem either.
I would like some advice on how to tackle my problem. I absolutely do want the bitmaps in memory, but perhaps I could limit the amount of slots available for bitmaps, keeping only the most frequently needed ones in memory and loading others on demand. This is probably a long shot, but perhaps I could request the OS to reserve more memory for me? I know for sure that the application will only run on devices that have enough RAM available anyway. Any help is appreciated, thanks in advance.
If you're using the same images on multiple forms, you should consider to keep those Bitmaps as static variables in a class that is accessible by all your forms.
public class AppBitmaps
{
public static Bitmap LogoBitmap = new Bitmap(...);
public static Bitmap ButtonBitmap = new Bitmap(...);
}
public class Form1
{
public Form1()
{
this.Control1.Image = AppBitmaps.LogoBitmap;
}
}
That way you only keep one instance of that image in memory, which should cut down the overall memory usage.
"getting a useful snapshot of the GC heap using RPM is hard" Maybe you can try some profiler for .NET CF, I have heard of EQATEC profiler if that helps you with the threads.
My approach to avoiding OOM errors is to not design for an MDI(Multiple Document Interface) type application, have only one form in memory) and setting to null all objects after they have been used (specially the "heavier ones" like XMLDocument).
Also, this might be relevant: OutOfMemoryException When Creating a Large Bitmap in CF.NET
If that is a snap shot of your application working at full tilt then I would suggest:
- It's another app that is running
- Your app pinvokes into an unmanaged memory leak
- The OS (customised CE?) has a leak
- or something else
精彩评论