Dynamic Proxy and Memory Footprint

A while back I published a post about dynamic programming with WCF using the dynamic proxy library that allows you to create WCF client dynamically at runtime. Thank you for using the sample and sending your comments. Frequently I get feedback about the memory usage of the applications using this library. It seems that if you create many dynamic proxies during the lifetime of your application, the memory footprint keeps growing. This is a common problem that you encounter when using any dynamically created assembly in your application. You need to aware of this issue and take appropriate measure to make sure that you are not leaking memory.

The dynamic proxy creates the proxy assembly at runtime; this assembly is stored in a temporary location on your file system and loaded in the memory of your app domain. Now if you do not need the dynamic proxy anymore, there is no way to unload this temporary assembly. There isn’t. You need to unload the entire app domain. So what should you do if you need to create and destroy many dynamic proxies in your application? Simply, isolate the code that is creating and using the dynamic proxy and run it in a different app domain. Once you are done, simply unload that app domain.

Here is a simple modification to the example program from the dynamic proxy library that runs the dynamic client in a new app domain. You will notice that the memory footprint of the application remains the same over large number of iterations.

class Program

{

    public static void Main(string[] args)

    {

        string serviceWsdlUri = "http://localhost:8080/WcfSamples/DynamicProxy?wsdl";

        if (args.Length > 0)

        {

            serviceWsdlUri = args[0];

        }

        for(int i = 0; i < 1000; i++)

        {

            AppDomain proxyDomain = AppDomain.CreateDomain("ProxyExecutionDomain");

            DynamicClient dynamicClient = new DynamicClient(serviceWsdlUri);

            proxyDomain.DoCallBack(

              new CrossAppDomainDelegate(dynamicClient.CrossAppDomainCallback));

            AppDomain.Unload(proxyDomain);

   GC.Collect();

        }

    }

}

[Serializable]

class DynamicClient

{

    string serviceWsdlUri;

    public DynamicClient(string serviceWsdlUri)

    {

        this.serviceWsdlUri = serviceWsdlUri;

    }

    public void CrossAppDomainCallback()

    {

        // create the dynamic proxy factory, that downloads the service metadata

        // and create the dynamic factory.

        Console.WriteLine("Creating DynamicProxyFactory for " + serviceWsdlUri);

        DynamicProxyFactory factory = new DynamicProxyFactory(serviceWsdlUri);

...