In my MVC application there is Castle Windsor used as it is described here:
https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-part-2-plugging-windsor-in.md

When "container.Kernel.ReleaseComponent(controller)" is called, this 
controller is not disposed and remains in memory forever - it introduce 
memory leak.
The reason for this must be:

There is only one difference, when you get a controller instance, there is 
called extension method, which adds some login functionality to controller:

       *protected override IController GetControllerInstance(RequestContext 
requestContext, Type controllerType)*
*        {*
*            if (controllerType == null)*
*            {*
*                throw new HttpException(404,*
*                    $"The controller for path 
'{requestContext.HttpContext.Request.Path}' could not be found.");*


*            }*

*           return 
((IController)container.Kernel.Resolve(controllerType)).AddControllerLoggingFunctionality();
  
         // if it is without extension methos, there is no memory leak:*

*           //return (IController)container.Kernel.Resolve(controllerType);*
*        }*

The controller instance looks like this:

<https://lh3.googleusercontent.com/-caNhjJ3C8Uc/WKr7UycBBaI/AAAAAAAAC6Q/T-pMPEje3NkSlz29whUja5nQeYZklYOiwCLcB/s1600/controller.JPG>

So, AddControllerLoggingFunctionality is responsible for memory leak.
This method is inside Logger class and use Castle DynamicProxy interceptor:

 *public static class Logger*
* {*
*        private static readonly Castle.DynamicProxy.ProxyGenerator 
proxyGenerator;*

*        static Logger()*
*        {*
*            proxyGenerator = new Castle.DynamicProxy.ProxyGenerator();*
*            
Castle.DynamicProxy.Generators.AttributesToAvoidReplicating.Add(typeof(ServiceContractAttribute));*
*        }*

*       public static TInterface 
AddControllerLoggingFunctionality<TInterface>(this TInterface 
implementation) where TInterface : class*
*        {*
*            if (implementation == null)*
*            {*
*                throw new ArgumentNullException("implementation");*
*            }*

*            if (!typeof(TInterface).IsInterface)*
*            {*
*                throw new Exception("Type of 'TInterface' must be 
interface.");*
*            }*

*            Castle.DynamicProxy.ProxyGenerationOptions options = new 
Castle.DynamicProxy.ProxyGenerationOptions();*

*            var origAttribs = 
implementation.GetType().GetCustomAttributesData();*
*            if (origAttribs != null)*
*            {*
*                foreach (var origAttrib in origAttribs)*
*                {*
*                    
options.AdditionalAttributes.Add(AttributeUtil.CreateBuilder(origAttrib));*
*                }*
*            }*

*            return 
(TInterface)proxyGenerator.CreateInterfaceProxyWithTarget<TInterface>(*
*                implementation,*
*                options,*
*                new 
ControllerLoggingInterceptor(implementation.GetType()));*
*        }*

*       private class ControllerLoggingInterceptor : 
Castle.DynamicProxy.IInterceptor*
*        {*
*            private readonly Type typeTarget = null;*
*            private readonly ILog logger = null;*

*            public ControllerLoggingInterceptor(Type type)*
*            {*
*                this.typeTarget = type;*
*                this.logger = LogManager.GetLogger(this.typeTarget);*
*            }*

*            public ControllerLoggingInterceptor()*
*            {*
*                this.logger = 
LogManager.GetLogger("NullTargetAutoLogger");*
*            }*

*            public void Intercept(Castle.DynamicProxy.IInvocation 
invocation)*
*            {*
*                bool success = false;*
*                string sbTraceMethod = null;*
*                long ticksBefore = 0;*
*                long ticksAfter = 0;*

*                try*
*                {*
*                    if ((this.logger != null) && 
this.logger.Logger.IsEnabledFor(log4net.Core.Level.Trace))*
*                    {*
*                        sbTraceMethod = 
GetControllerActionName(invocation);*
*                        logger.TraceFormat("Entering {0}", sbTraceMethod);*
*                    }*

*                    ticksBefore = DateTime.Now.Ticks;*
*                    invocation.Proceed();*
*                    ticksAfter = DateTime.Now.Ticks;*
*                    success = true;*
*                }*
*                catch (Exception)*
*                {*
*                    ticksAfter = DateTime.Now.Ticks;*
*                    success = false;*
*                    throw;*
*                }*
*                finally*
*                {*
*                    if (this.logger != null*
*                     && 
this.logger.Logger.IsEnabledFor(log4net.Core.Level.Trace))*
*                    {*
*                        logger.TraceFormat("Leaving {0} with success: {1} 
elapsed time: {2}ms", sbTraceMethod ?? "[no info]", success, 
TimeSpan.FromTicks(ticksAfter - ticksBefore).TotalMilliseconds);*
*                    }*
*                }*
*            }*

*            private static string 
GetControllerActionName(Castle.DynamicProxy.IInvocation invocation)*
*            {*
*                ParameterInfo[] methodParams = 
invocation.Method.GetParameters();*
*                ParameterInfo activityParameterInfo = 
methodParams.FirstOrDefault(x =>*
*                    
x.ParameterType.Equals(typeof(System.Web.Routing.RequestContext)));*

*                if (invocation != null && invocation.Arguments != null)*
*                {*
*                    System.Web.Routing.RequestContext rq = 
invocation.Arguments[activityParameterInfo.Position] as 
System.Web.Routing.RequestContext;*

*                    if (rq != null && rq.RouteData != null && 
rq.RouteData.Values.Count >= 2)*
*                    {*
*                        return String.Format(*
*                            "{0}.{1}()",*
*                            rq.RouteData.Values["controller"],*
*                            rq.RouteData.Values["action"]);*
*                    }*
*                }*
*                return "UNKNOWN";*
*            }*
*        }*
*}*
The controller object is like this:

What should I change to avoid memory leak and keep functionality as it is?

Thanks

-- 
You received this message because you are subscribed to the Google Groups 
"Castle Project Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to castle-project-users+unsubscr...@googlegroups.com.
To post to this group, send email to castle-project-users@googlegroups.com.
Visit this group at https://groups.google.com/group/castle-project-users.
For more options, visit https://groups.google.com/d/optout.

Reply via email to