I'm trying to get to the bottom of what appears to be a memory leak in a customer's VB.NET ASP.NET application (we didn't write the code).
Two things spring out at me:
They have a data access assembly with a single data access class which when instantiated runs this code in the constructor:
public SqlServer(string connString) { List<WeakReference> list = __ENCList; lock (list) { __ENCList.Add(new WeakReference(this)); } // misc other tasks of no further interest }
__ENCList
is declared as:private static List<WeakReference> __ENCList;
on the class.What's the intention behind this? I did read somewhere that VB.NET uses this for Edit and Continue purposes, but understood it wouldn't be generated in release builds. Both .NET Reflector and ILDASM show that this is in the production release build data access assembly.
Digging about with WinDbg and doing a
!dumpheap -stat
I see this:
66101820 10269 451836 System.Web.UI.Control+OccasionalFields 7a5eecbc 22936 458720 System.Collections.Specialized.ListDictionary+DictionaryNode 79331754 2285 470684 System.Char[] 648c91f4 10438 501024 System.Configuration.ConfigurationValues 7a5e9eb0 37978 607648 System.Collections.Special开发者_如何学运维ized.NameObjectCollectionBase+NameObjectEntry 648c9434 32651 653020 System.Configuration.ConfigurationValue 7a5e27a0 6567 788040 System.ComponentModel.ReflectPropertyDescriptor 7932ea08 18318 879264 System.Signature 79332b54 42528 1020672 System.Collections.ArrayList 79333178 18348 1027488 System.Collections.Hashtable 79332cc0 7535 1346108 System.Int32[] 7932dd5c 43220 2420320 System.Reflection.RuntimePropertyInfo 7932fde0 72902 4082512 System.Reflection.RuntimeMethodInfo 79333274 19162 4321680 System.Collections.Hashtable+bucket[] 79333594 3475 4638780 System.Byte[] 793042f4 134867 6473100 System.Object[] 000f6f80 394 24556172 Free 79330b24 174120 26678884 System.String Total 1098618 objects Fragmented blocks larger than 0.5 MB: Addr Size Followed by 33b7b58c 2.1MB 33d99cf4 System.Data.ProviderBase.DbConnectionClosedBusy 41635a50 0.6MB 416c873c System.Data.ProviderBase.DbConnectionClosedBusy
Is that an unusually high number of System.Reflection.RuntimeMethodInfo
objects?
- The server has 49 sites running in a single application pool.
- All sites are identical (each one is a rebrand site)
- The binaries in each site's
/bin
folder are identical - The server is running Windows 2003 32bit Standard SP2
- The application is written in ASP.NET 2.0 (Web Forms, not MVC)
- .NET 2.0 is fully patched to SP2 (via .NET 3.5 SP1 update).
- The paging file is set to grow to 4GB (recommended max I read somewhere)
The application does use a Infragistics Web control suite (v10.2):
Infragistics35.Web.v10.2.dll
Infragistics35.WebUI.Shared.v10.2.dll Infragistics35.WebUI.UltraWebGrid.v10.2.dll Infragistics35.WebUI.UltraWebTab.v10.2.dll Infragistics35.WebUI.WebDataInput.v10.2.dll
The symptoms are Out Of Memory exceptions when we see Virtual Bytes for the process hit ~2GB and private bytes hit around 900MB.
The server has <deployment retail="true" /> configured in
machine.config`.
The builds are release builds and debug="false
set configured in the <compilation/>
section.
Any advice would be useful.
To answer your first question, weak references are used to hold a reference to an object without preventing that object from being garbage collected. In this case, it appears they are maintaining a list of all instances of the Server class. Such a list would need to use weak references because otherwise no instances of that class would ever be deleted once created unless they were removed from that list first. What they are using that list of instances for I cannot say without seeing the rest of the code, but they might be doing some sort of cacheing or connection pooling (although the later would be bad because ado.net already does this for you).
Also, know that the weak references themselves are objects, and so unless the references that are no longer referencing a live object are removed from the list, they will cause memory to be leaked. However, they are small objects, and are unlikely to cause a problem unless there are a lot of Server instances being created.
As for your second question, I don't know how many MethodInfo objects are normal for this type of environment. However, I do remember reading in the days of .Net 2.0 that reflection objects are never unloaded after they are requested within a given application domain. As far as I know, that hasn't changed. But, since the runtime will only create at most one such object per unique method, that's unlikely to be a problem unless they're using some kind of runtime code generation. Otherwise, the maximum number of such objects that could be created would be limited to the number of methods in the assemblies used by the application.
精彩评论