Is there a way to release an object that was accessed using late-binding (i.e. created by the Activator.CreateInstance() method)?
I have an application that transforms files from one format to another. The assemblies that perform these translations live in a folder in my application directory.
When the application first starts up, I can delete these assemblies from the translation folder without any errors. However, once I process a document through the application (and have bound to one of the translation assemblies using late-binding), I can no longer delete the translation assemblies. At this point, I'm receiving an error message stating that the file is "in use by another application".
Is there a way to "release" the late-bound object in my application once I'm finished using it?
Once an assembly is loaded into an application domain it'll remain until the app domain shuts down.
To get around this load the assembly into it's own application domain, for example:
AppDomain app = AppDomain.CreateDomain("PlugInDomain");
ObjectHandle objectHandle = app.CreateInstanceFrom(assemblyPath,
"MyNamespace.MyComponent");
MyComponent component = (MyComponent) objectHandle.Unwrap();
// do stuff
// Now kill app domain, assembly can be overwritten after this.
AppDomain.Unload(app);
Once an assembly is loaded into the executing AppDomain, it cannot be unloaded (regardless of whether it is creating via reflection with Activator.CreateInstance).
The recommended approach here is to implement a secondary AppDomain with a lifetime that can unload when it wants to dispose the assemblies.
There are tons of examples, but here is one:
http://www.dotnet247.com/247reference/msgs/28/142174.aspx.
Since managing the lifetime of secondary AppDomains can be a pain, as an alternative, if you are using ASP .NET and are looking to load many dynamic assemblies, you can check when your current AppDomain becomes saturated with dynamically loaded assemblies by binding to the AppDomain.CurrentDomain.AssemblyLoaded event and keeping count, then requesting the hosting environment recycle the current AppDomain when it hits a critical number (say 500) like:
HostingEnvironment.InitiateShutdown();
Related
Looks like I'm trying to do something that other's haven't run into again. Atleast, from Google searching it seems like this is pretty unique.
I have a server running with a directory full of dlls. Each dll is used to process a certain type of order and managed by different people. When an order comes in, there is a table that determines which dll to spin up, run it and then spin it down (free from memory).
The process we started with was:
Create an AppDomain
Load needed dll into the domain
Run the code we need
Unload the AppDomain
The issue we had with this was the server would run out of memory or we would get "token errors". I think the issue is that we call some 3rd party pascal dlls I don't think are getting freed.
We updated our the process to:
Create an AppDomain on process load
Load the dll into this "global" AppDomain
Run the dll's code
This got rid of our memory issues and we have recieved zero token errors. However, when we want to move a dll from our test server to our production server we have to kill the whole service, and then the dlls are not locked in memory. Then reprocess any orders that died with the service and any that came in while the service was down.
I've worked with the group and tried to unload the AppDomain, but once it is unloaded it doesn't just free dll's that are running, it basically kills the whole domain. I've considered moving this dll loader to it's own System.Process, so that the OS can clean up the memory when the process ends. However, I'm not sure how to have one Process run code in another Process. This plan seems like basic OS security features would prevent it because virus' would have a heyday.
Does anyone have an idea how we can run dll's in an AppDomain and then having them unlocked from memory so that they can be updated? (Without creating and disposing many AppDomain because they don't seem to clean everything up.) It would be great to have a memory pool that I can nuke and but .NET isn't about manual memory management.
I'm trying to create a plugin system. For now, I have a system which can load and unload some dynamic libraries on runtime.
I create a AppDomain this way:
AppDomain is a private member variable.
RemoteLoader is a private member variable.
AppDomainSetup setup = new AppDomainSetup
{
ApplicationName = assemblyName,
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
};
AppDomain = AppDomain.CreateDomain(domainName, null, setup);
remoteLoader = (RemoteLoader)AppDomain.CreateInstanceAndUnwrap(assemblyName, typeName);
RemoteLoader keep the list of available Assemblies, can create objects and find objects.
The AppDomain is correctly created. And when I unload, I can see the AppDomain disappearing from module list on Visual Studio.
I'm running Jetbrains dotMemory to find memory leak.
My test for now is:
Load the service, without any plugin
Snapshot
Load some plugin
Let the plugin work for a while
Unload the plugin (unloading the entire AppDomain)
Snapshot
When I compare the two snapshots I can see some objects that never disappear.
Some strings with following texts:
"STEP_Service.Contract.ModuleBase, STEP_Service.Contract, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
"/6ceffbca_d8b4_43be_91ac_39b8cb09ef37/s5bbue3ddey9xxfuevnmvmv9_158.rem"
"c6360995_32bd_46d9_b83b_3fbac3c58c6a/w1ntjmpe4s+1zp1rkmrio_dy_141.rem"
I can't figure out what is happening. The Key Retention Paths show me that:
[
The Stack Trace:
Some RuntimeMethodInfo are leaking:
Other objects like:
No exceptions is thrown by unload function or any place.
My Dispose method call the Unload that is defined like this:
/// <summary>
/// Unloads the plugins
/// </summary>
public void Unload()
{
if (AppDomain == null)
throw new NullReferenceException(nameof(AppDomain));
AppDomain.Unload(AppDomain);
remoteLoader.Dispose();
AppDomain = null;
remoteLoader = null;
}
I know I didn't provide so much code but I really don't know exactly what code I need to give.
If something is missing please ask for.
Every class is derived from MarshalByRefObject and just for test I marked a lot of fields as NonSerializable.
On my concept when I call static method Unload of AppDomain class, everything inside the AppDomain must be released.
EDIT
After a couple minutes executing my service I can see the objects:
Seems like the CrossAppDomainData and other objects (holded by it self) is growing. The object is placed at Generation 2 of GC.
EDIT
After one hour, I can see 2794 NewObjects of type CrossAppDomainData and a couple other objects holded by it
CrossAppDomainData
CrossAppDomainSink
Int64
EDIT
After couple hours, I can see around 32k objects of CrossAppDomainSink, CrossAppDomainData and Int64. The memory of my service grown up from 8k to 17k
EDIT
I discovered the problem but I don't know why this is happening.
To discover the issue, I recreated my service step by step.
Everthing works fine when I load/unload appdomains a lot of times. Everything is released properly and the memory is ok.
But in the next step which is load that dll on another application to have the power of unload, update and load again, something is leaking.
On other words, my actual scenario is:
Service which loads a Core DLL on another AppDomain
The Core DLL can load plugins on runtime
The Core DLL can be changed on runtime
FileSystemWatcher can monitor the folder for changes on CoreDLL. When this happen, the service unloads the CoreDLL after all work is done, loads the new one and start the work again.
The loaded dll (CoreDLL) do the hard work of loading the plugins, watch the plugin folder, and other things. The service only exists to carrie the CoreDLL to have the power of update himself.
So... why the objects mentioned before are leaking? The calls are made by the CoreDLL and not by the service.
I'm working on an application extension system (plugins) where each plugin should be isolated into a separate AppDomain. The work is about to be completed, but there is still one important question about how long an AppDomain should live.
The system is used server-side, and it uses the plugins regularly, let's say it should call each plugin in every ten minutes once. In this case, taking every kind of overhead of AppDomains into count, which is more appropriate?
Create the AppDomain instances once and keep them alive for the entire life-cycle of the application (so each plugin call will go into the same AppDomain per plugin).
Create the Appdomain instances for each plugin calls and then Unload them.
Using AppDomain.CreateDomain(...):
1). create new app domain for each plugin and keep it alive during the entire application lifetime
pros: no overhead for: creating app domain, loading .dlls, etc on each plugin call
cons: all .dlls from all app domains are eating the memory during the entire application lifetime; need to be careful with static variables; no sandboxing between calls (if one breaks the app domain then all calls will fail)
2). create new app domain for each plugin call and unload after
pros: sandboxing between calls; releasing memory between calls
cons: overhead for: creating app domain, loading .dlls, etc on each plugin call
If you have many calls per plugin and large batch of .dlls for it, use option 1
If you have many calls per plugin and small batch of .dlls for it, use option 2
If you have few calls per plugin and small batch of .dlls for it, use option 2
If you want sandboxing between calls, use option 2
I read the concept about Application Domain in .NET. However, I don't know when to use it. A application domain is working as a thread in a process. A process will have more than or equal one application domain. However, I can deploy a process with multi-threading without using application domain.
Anyone can tell some examples to use it in practice. There are source code for examples are good. And I wonder that there are any Microsoft's applications to use this technology.
Thanks.
If you load a dll in your main AppDOmain you can't unlod it. But if you load the .dll in an AppDOmain you can unload the AppDomain and so unload the dll. Like that you can load and unload dll.
And with Addin I saw that you can load plugin in AppDomain with security, in order that the plugin can not compromise the main software security.
I would like to explain the usage of AppDomains in a real world design problem from one of my earlier project.
Basically that project is a port scanner for some information. So we had 6 ports, and we are suppose to scan 6 ports in parallel. Of course we could have used threads, but then isolation would not be possible at all. We wanted every port functionality i.e scanning should be completely isolated and even its data storage and other functionality to be independent.
So what we did was, we used AppDomain concept in loading on of our dll which does this scanning job and few more (proprietary logics) into 6 AppDomains we had created for each port. Infact, this dll spawns more thread internally to do various jobs once you scan the port for some data. Hence we have completely isolated each port scanning and when user wants to stop scanning for one of the port (via UI selection) then we just have to gracefully unload this AppDomain.
Hope it was some help to you :)
MSDN really gives a clear picture here of what AppDomains are actually for: http://msdn.microsoft.com/en-us/library/system.appdomain.aspx
Application domains, which are represented by AppDomain objects, help provide isolation, unloading, and security boundaries for executing managed code.
Use application domains to isolate tasks that might bring down a
process. If the state of the AppDomain that's executing a task becomes
unstable, the AppDomain can be unloaded without affecting the process.
This is important when a process must run for long periods without
restarting. You can also use application domains to isolate tasks that
should not share data.
If an assembly is loaded into the default application domain, it
cannot be unloaded from memory while the process is running. However,
if you open a second application domain to load and execute the
assembly, the assembly is unloaded when that application domain is
unloaded. Use this technique to minimize the working set of
long-running processes that occasionally use large DLLs.
I have an asp.net website that uses a web application and they are both in the same application pool (with 1 worker process). The website has a httpmodule loaded in it's web.config file and curiously both the main website and the application will be served by seperate instances of the httpmodule. Why is this? Since they are in the same process it seems like they should use one instance.
Also, if I try to use static variables in the application they will point to different objects than in the asp.net website. Same question as before since they are in the same process shouldn't they be the same object or does .net imposs some sort of boundary inside of the process?
IIS creates a seperate AppDomain for each applicatiopn. These AppDomains live inside the same operating system process, but can be treated like separate processes from the viewpoint of your managed code. I.e. they don't share loaded assemblies, memory, etc.
http://www.odetocode.com/articles/305.aspx
http://weblogs.asp.net/owscott/archive/2007/09/02/application-vs-appdomain.aspx
http://msdn.microsoft.com/en-us/library/system.appdomain(VS.85).aspx