- Abhinaba’s blog
- What’s new in Windows Mobile 6.1 and 6.5 around memory
- Dynamic assembly unloading
Again again again… I’ve discussed about Memory Management in my very first post, which I suggest reading as it may help you on avoiding memory leaks and also improving memory management of your NETCF application. I’ve discussed about this other times, and to demonstrate how sensible this topic is, recently Abhinaba Basu (Developer working on the .NET Compact Framework team) started blogging about how the NETCF runtime handles memory: thanks Abhinaba for all those details!
So, why am I still talking about memory?? Because that’s the scarcest resource whose lack mobile developers have to face sometimes… btw let me digress: remember that Windows Mobile 6.1 and 6.5 help a lot ISVs on preventing OOM by modifying some details of the memory management, in particular to alleviate memory pressure on the process slot 0 basically (considering all the "drivers" that OEMs have come up with, which need to be loaded by device.exe process — thus lowering the DLL Load point (in previous versions of the OS)). Doug Boling discussed about this here.
Obviously a downside for this is that there’s less room for memory-mapped files in the Large Memory Area (LMA), but, apart from some special circumstances, this shouldn’t affect ISVs’ job, considering also that the LMA may be used by the OS and by other applications, therefore ISVs shouldn’t expect it to be totally available for their usage.
Also, I’m still talking about memory because from time to time I got questions like “… ok, so why don’t we dynamically load and unload assemblies?”. When this question arises, I usually answer suggesting to start by reading some quite old references:
As documented here, “[…] To unload managed code running in a process from memory so that memory can be used for other purposes, the host must unload the application domain in which the code is running. Individual assemblies or types cannot be unloaded.”. A quite complex “trick” (I wouldn’t really recommend for NETCF applications) is to create a new AppDomain (AppDomain.CreateDomain is supported by the NETCF) and load an assembly into it. The point is that as soon as you try to create objects from that assembly which is loaded into the new AppDomain, the assembly will be loaded into the current AppDomain. In order to solve this problem, you have to use a middle assembly, which is loaded into both the current AppDomain and the new AppDomain. Once the new AppDomain is unloaded, the assembly will be unloaded from the memory as well. However, the middle assembly, will stay in the memory. This approach might be known among DESKTOP .NET developers: I don’t know if anyone has ever tried to implement this within a NETCF application.
IN ANY CASE, assemblies are loaded into the system’s 1GB area, therefore the benefit would only be for PHYSICAL memory in this case (and for the JIT-ed code). And we’re usually talking about roughly 25% of the size of the assembly. If you only need to have certain assemblies loaded at certain times, but never all at once then AppDomains can help; if you plan to have all your assemblies loaded simultaneously then AppDomains don’t offer much (for memory pressure relief).
Note: what if an assembly depends on a native DLL (so loaded into the 32MB process slot) for example via P/Invoke? When the assembly is unloaded (by destroying the AppDomain), starting on NETCF v3.5, if the native DLL is used only by that assembly then its virtual memory is released from the process slot.