2
votes

I have a memory leak and I am having a really hard time trying to figure out where the problem is. The ASP.NET process is raising to 1GB every now and then. I have followed the instructions on this page (http://humblecoder.co.uk/tag/windbg) and the !gcroot command returns the following (last x lines). I have looked at all my OracleConnections and OracleCommands and they appear to be closed and disposed correctly:

   6523dfd4      282        28200 System.Data.SqlClient.SqlParameter
    0e90d850      548        28496 System.IO.MemoryStream
    67b71a0c     1461        29220 System.Transactions.SafeIUnknown
    7a5ee588     1924        30784 System.Collections.Specialized.ListDictionary+NodeKeyValueCollection
    648c91f4      665        31920 System.Configuration.ConfigurationValues
    7a5e5d04     1342        32208 System.Threading.Semaphore
    652410f8      670        34840 System.Data.ProviderBase.DbConnectionPool+PoolWaitHandles
    6613228c     1319        36932 System.Web.Security.FileSecurityDescriptorWrapper
    66106948     2449        39184 System.Web.UI.AttributeCollection
    0e8ff780     2021        40420 Microsoft.Win32.SafeHandles.SafeLsaPolicyHandle
    01e34730      336        43008 Oracle.DataAccess.Client.OracleDataReader
    648c9434     2218        44360 System.Configuration.ConfigurationValue
    7a5ea0e4     1918        46032 System.Collections.Specialized.ListDictionary+NodeKeyValueCollection+NodeKeyValueEnumerator
    7a5eaaa8     3088        49408 System.Collections.Specialized.NameObjectCollectionBase+NameObjectEntry
    652435c4     1138        59176 System.Data.SqlClient.SqlBuffer
    0e912c9c     2491        59784 System.Collections.ArrayList
    0e9132c0     1236        69216 System.Collections.Hashtable
    6614bf64       45        69660 System.Web.Caching.ExpiresEntry[]
    0e8ff7d8     4042        80840 Microsoft.Win32.SafeHandles.SafeLsaMemoryHandle
    66105ff4     5434        86944 System.Web.UI.StateBag
    01e364c8     5686        90976 Oracle.DataAccess.Client.OpoSqlValTimeoutCtx
    0e912e08     1007        91556 System.Int32[]
    7a5ee300     3942        94608 System.Collections.Specialized.ListDictionary+NodeEnumerator
    01e35ef8     7918        95016 Oracle.DataAccess.Client.OpoSqlRefCtx
    01e353bc     6043        96688 Oracle.DataAccess.Client.MetaData
    0e8f83e8     5017       100340 Microsoft.Win32.SafeHandles.SafeLocalAllocHandle
    7a5ef738     6284       125680 System.Collections.Specialized.HybridDictionary
    7a5ef7f4     5143       144004 System.Collections.Specialized.ListDictionary
    661060d0    10908       174528 System.Web.UI.StateItem
    0e91189c      533       184492 System.Char[]
    6610d15c     2426       203784 System.Web.UI.WebControls.TableCell
    01e362ec     7918       221704 Oracle.DataAccess.Client.OracleXmlQueryProperties
    7a5ef8b4    11231       224620 System.Collections.Specialized.ListDictionary+DictionaryNode
    65242390     1814       232192 System.Data.SqlClient._SqlMetaData
    0e8f832c    12124       242480 Microsoft.Win32.SafeHandles.SafeTokenHandle
    01e36444     7918       253376 Oracle.DataAccess.Client.OracleXmlSaveProperties
    0e8f7ca8    13394       267880 Microsoft.Win32.SafeHandles.SafeWaitHandle
    0e9133bc     1255       267912 System.Collections.Hashtable+bucket[]
    0e8f7a98    12048       289152 System.Threading.ManualResetEvent
    0e8e443c     7886       385508 System.Object[]
    01e34b60     6456       387360 Oracle.DataAccess.Client.OpoConRefCtx
    01e33860     6432       668928 Oracle.DataAccess.Client.OracleConnection
    01e34f9c     6439       824192 Oracle.DataAccess.Client.OpoConCtx
    01e34038     7918      1171864 Oracle.DataAccess.Client.OracleCommand
    000dfbe0       70      5839608      Free
    0e9136dc     2622     17492932 System.Byte[]
    0e910c6c    56049     19472876 System.String
    Total 283875 objects
1
The heap included doesn't explain a 1 GB memory footprint. Was the dump created at the time of the memory peak? If so you need to look elsewhere for the problem. Are you generating assemblies on the fly perhaps?Brian Rasmussen
@Brian Rasmussen,thanks. I am not creating assemblies on the fly. The dump was created when the process was over 1GB. There is a lot of String concatenations. I am wandering if the 56049 Strings in memory could be the problem?w0051977
String concatenations may be a problem, but the dump doesn't show a huge number of strings taking up lots of memory. All .NET process will have a lot of strings. Looking at the dump string don't seem to be the problem. You can do a !eeheap to inspect the other heaps. Also, how big is the dump file?Brian Rasmussen
@Brian Rasmussen, the dump file is 1.3GB. I used TinyGet to stress test the website creating 5 threads and 10 loops. I did this ten times in succession. The webpage I targeted takes some time to run. The process memory rose to 900MB and then just at the end fell back to 200MB. It is confusing.w0051977
Based on the information you have given, it doesn't sound like you have a real memory leak. If the memory usage is climbing this may be due to the string concatenations, but since you say that memory usage drops again it sounds like all the temporary strings are actually being reclaimed as expected. If you want to reduce memory usage you may be better off using StringBuilder to handle the concatenations.Brian Rasmussen

1 Answers

0
votes

If mem usage drops to 200 MB after a time, this shows your memory is beeing collected, but you still might have a memory missuse issue. this dump doesn't show alot, but if it was taken when the process is 1GB as you said, you can still use it: 1) use !gcroot on several objects, to see how they are attached to the memory (i would check the DB usage, it seems you have a large amount of oracle connections (6432), and alot of other DB stuff floating around.) like this:

!dumpheap -MT <mt = the left most number>

objects will show with memory addresses

!gcroot <address>

an object stack will show displaying how the object is attached to the memory tree. a sample of this process

2) check performance counters (start->run->perfmon) add these counters: - .Net Clr Memory-> #bytes all heaps - Process->private bytes calculate the difference between them - this is the memory consumed by unmanaged resources (like DB client objects) check this in low memory and in high memory scenarios, and you will see if the memory consumption is mostly due to Managed memory (all heaps) or unmanaged. 3) if the memory is unmanaged, it's still likely to be held by managed objects, as the main application is managed, so making sure you free unmanaged resources after you are done with them is key. (close DBConnections, dispose DBCommands, close file handles, free COMObjects etc.)

Hope this helps, Amit.