2

I have been hitting my head against the wall for the last couple of days trying to figure out the an appdomain issue. I have created a small windows service that runs plugins. The way it works is, each plugin is a dll that gets loaded into it's own seperate appdomain using "CreateInstanceAndUnwrap" and i keep a reference to the appdomain and once the plugin completes, i shut down the appdomain that is created for that plugin.i'm using shadow copy to allow updates to the plugins while they are running in the framework.Ok good till now. It has run for 6 months perfectly untill last week when i decided to put the core functionality of the framework into a seperate DLL also and execute that dll in a seperate appdomain .So the way it works right now is :

Windows service comes up.the core dll is loaded and executed using CreateInstanceAndUnwrap which in turn is responsible for running the plugins in their own seperate appdomains (using CreateInstanceand..)

I have couple of different locations for assemblies : Bin Folder (Bin of the windows service holds only dlls used by the service) Core DLLs Folder (Core dlls get dropped in here) References Folder (any references get dropped in here) Plugins Folder (plugins get dropped in here)

I resolve any unfound dll by hooking up to each appdomain's onassemblyresolve handler. So this means that the dlls can get loaded from over the network.

Now the problem is the windows service ran for one day and the memory went as hight as 1.5G. I created a dump of the memory and seems like loaded modules are only 100MB of the whole 1.5G so i dont know where all this memory is going to. Using debugdiag I saw an alert for heap fragmentation but i have no idea where i should start to diagnose the issue. Usually when the framework runs for a day it consumed something like 100M. Also this is not related to the plugins either as when i rolled back my changes to the framework the memroy usage became normall as before. When i create the appdomains for plugins, i switch the basePath and the bin path of the appdomain to CORE and References folders that have most of the dlls in there in hope that the assembly resolve gets called less often.

I looked at fusion logs and also read a little bit more about load contexts like default,from, and none but im not sure if thats the right path to take.

Any ideas?

James
  • 103
  • 2
  • 7
  • i use an interface to get the proxy of the second appdomain and recently a bug came up that the cast was erroring out because of the famous "invalid cast from type exception" so i switched the return cast to a dynamic type instead :D i know this is not a good solution to the problem but it solved the casting issue.i'm guessing multiple versions of the interface dll is being loaded into the calling appdomain and thats why it is giving the type cast exception.i create the main appdomain and also the plugin appdomains using createinstanceandunwrap.for resolve asselmbly event i use "LoadFrom" – James Oct 28 '11 at 03:12

1 Answers1

1

I think this:

when i decided to put the core functionality of the framework into a seperate DLL also and execute that dll in a seperate appdomain .So the way it works right now is :

Windows service comes up.the core dll is loaded and executed using CreateInstanceAndUnwrap which in turn is responsible for running the plugins in their own seperate appdomains (using CreateInstanceand..)

might be running afoul of this:

From http://msdn.microsoft.com/en-us/library/3c4f1xde.aspx

If you make an early-bound call to a method M of an object of type T1 that was returned by CreateInstanceAndUnwrap, and that method makes an early-bound call to a method of an object of type T2 in an assembly C other than the current assembly or the assembly containing T1, assembly C is loaded into the current application domain. This loading occurs even if the early-bound call to T1.M() was made in the body of a DynamicMethod, or in other dynamically generated code. If the current domain is the default domain, assembly C cannot be unloaded until the process ends.

In which case, you might be able to use Reflection to execute the "appropriate" call to eliminate the early-binding.

Community
  • 1
  • 1
Nathan
  • 10,593
  • 10
  • 63
  • 87
  • I will investigate further if this is what is happening but when i debugged the windows service i did not see any duplicate dlls being loaded or the main appdomain being loaded with the dlls from the plugins at all. it seemed all fine, even when i dumped the 1.5G running service, the debugdiag did not show any signs of that. Loaded modules = 100M ! – James Oct 28 '11 at 18:13
  • Also the doc is saying that : "This loading occurs even if the early-bound call to T1.M() was made in the body of a DynamicMethod, or in other dynamically generated cod". So this would mean that using reflection will probably not work either.(If that is the case) – James Oct 28 '11 at 20:40
  • Reflection can still be used to call code that is not dynamically generated. Using Reflection MethodInfo for example, does not generate any dynamic code, and it can be used to invoke methods defined at compile time. So I think it is still a possibility to break early binding. – Nathan Oct 28 '11 at 21:40
  • I tried this but GetMethod does not seem to be working on the dynamically generated proxy. I'm getting a "method does not exist on system.marshalByRef" exception. – James Oct 31 '11 at 19:47
  • also it seems like this MIGHT be the cause of memory issues in my case, i found out that some of the plugins are actually getting loaded into the initial appdomain. (but they should not be taking 1.5G so im still not sure) – James Oct 31 '11 at 19:50
  • Definitely a puzzle. You might have a look at http://stackoverflow.com/questions/2634858/how-do-i-reflect-over-the-members-of-dynamic-object in terms of solving the reflection issue - though that is a slightly different case (I don't believe you are using the dynamic keyword anywhere). But it might provide some hints on providing some additional metadata to reflection - though honestly with this particular aspect of reflection, I'm getting a little out of my realm of experience. – Nathan Nov 01 '11 at 04:34
  • Just to be clear, when you say you're still not able to resolve the issue, are you still speaking in terms of not being able to get the reflection to work? Or were you able to get reflection to work and it didn't fix the memory issue? – Nathan Nov 01 '11 at 04:39
  • One other possible fix comes to mind - wrap the proxy call that you invoke with reflection inside a compile-time class, and instead invoke the wrapped (compile-time) method via reflection - so that you aren't directly reflecting on a MarshalByRef object. – Nathan Nov 01 '11 at 04:45
  • I could not get the reflection to work but i will try the other approach you just mentioned. – James Nov 02 '11 at 22:40