I found this post about the memory leak problem in LRUMap and I would ask to check this problem again, please.
On Sunday, December 14, 2008 at 4:18:21 PM UTC-2, Davy Brion wrote: > > just fixed it in the trunk (revision 3953) > > thanks for finding this :) > > On Thu, Dec 11, 2008 at 11:08 PM, Rasmus Kromann-Larsen <[email protected] > <javascript:>> wrote:1. > >> >> It is an issue in the LRUMap. >> >> This passes: >> >> [Test] >> public void SimpleLRUTest() >> { >> LRUMap map = new LRUMap(128); >> >> for (var i = 0; i < 200; i++) >> map.Add("str" + i, i); >> >> Assert.That(map.Count, Is.EqualTo(128)); >> } >> >> and this fails: >> >> [Test] >> public void SimpleLRUTest2() >> { >> LRUMap map = new LRUMap(128); >> >> for (var i = 0; i < 200; i++) >> map["str" + i] = i; >> >> Assert.That(map.Count, Is.EqualTo(128)); >> } >> >> Checking the NHibernate source, the Add method has bounds checking for >> the cache-size while the indexer's set method is just: >> >> set >> { >> base[key] = value; >> } >> >> Woo. >> >> >> On Dec 11, 11:00 pm, Rasmus Kromann-Larsen <[email protected]> wrote: >> > Oh... I just tested it out on my integration test - it failed single >> > threaded too. Then I wrote some reflection code to inspect the fields >> > etc - and finally I got the idea of testing the SoftLimitMRUCache >> > instead. >> > >> > This test fails: >> > >> > [Test] >> > public void SimpleTest() >> > { >> > SoftLimitMRUCache cache = new SoftLimitMRUCache(128); >> > >> > for(var i=0;i<200;i++) >> > cache.Put("str"+i, i); >> > >> > Assert.That(cache.Count, Is.EqualTo(128)); >> > } >> > >> > Atleast on my setup - can anyone test it on the trunk? :-) >> > >> > It appears to be a variation of the same problem as Ben described. >> > >> > On Dec 11, 10:47 pm, "Ben Lovell" <[email protected]> wrote: >> > >> > > Long shot but I had experienced a similar issue which was related to >> > > caching. Check this out: >> > >> > >http://jira.nhibernate.org/browse/NH-604 >> > >> > > Bhttp://benl.wordpress.com >> > >> > > On Thu, Dec 11, 2008 at 9:37 PM, Ayende Rahien <[email protected]> >> wrote: >> > > > I can tell you for sure that this is not something that we have >> seen in >> > > > other apps.Although this is way too deep in the guts of NH for an >> > > > extension to change. >> > >> > > > On Thu, Dec 11, 2008 at 11:28 PM, Rasmus Kromann-Larsen < >> > > > [email protected]> wrote: >> > >> > > >> Well, obviously it isn't - I just haven't noticed it before >> switching >> > > >> to NHibernate 2. >> > >> > > >> I am using Linq to NHibernate and Fluent NHibernate too though, but >> > > >> they shouldn't affect stuff this deep in the SessionFactory? >> > >> > > >> Odd. I guess I will have to dig deeper. >> > >> > > >> On Dec 11, 10:18 pm, "Ayende Rahien" <[email protected]> wrote: >> > > >> > It is not multi threaded safe, but I would say that it should >> certainly >> > > >> > work. >> > >> > > >> > On Thu, Dec 11, 2008 at 7:11 AM, Rasmus Kromann-Larsen >> > > >> > <[email protected]>wrote: >> > >> > > >> > > Hi, >> > >> > > >> > > I have been trying to pin down a memory leak in my wep app >> these past >> > > >> > > few weeks - and digging into my application with WinDbg >> revealed >> > > >> > > something fishy with the NHibernate SessionFactory in memory. >> > >> > > >> > > Context: It's a standard ASP.NET application using NHibernate >> > > >> > > 2.0.0.4000. I only use 1 SessionFactory since that seems to be >> the >> > > >> > > defacto standard - and my Sessions are disposed using >> something along >> > > >> > > the lines of Ayende's unit of work. >> > >> > > >> > > I have been analyzing a memory dump of a ~800mb .NET heap to >> figure >> > > >> > > out why it kept growing. One thing I found was around 1.9 >> million >> > > >> > > NHibernate.SqlCommand.SqlStrings and ~90000 HQLQueryPlans >> > >> > > >> > > MT Count TotalSize Class Name >> > > >> > > 0f7fb3e4 92382 3695280 >> NHibernate.Engine.Query.HQLQueryPlan >> > > >> > > 0eafd714 1939496 31031936 NHibernate.SqlCommand.SqlString >> > >> > > >> > > Digging down into the roots of one of these SqlStrings >> revealed that >> > > >> > > it was being stored in the query plan cache in the >> SessionFactoryImpl: >> > >> > > >> > > 067016bc(NHibernate.Impl.SessionFactoryImpl)-> >> > > >> > > 06702470(NHibernate.Engine.Query.QueryPlanCache)-> >> > > >> > > 06703050(NHibernate.Util.SoftLimitMRUCache)-> >> > > >> > > 067030a0(NHibernate.Util.LRUMap)-> >> > > >> > > 067030d4(System.Collections.Hashtable)-> >> > > >> > > 0c8af170(System.Collections.Hashtable+bucket[])-> >> > > >> > > 02e30ccc(NHibernate.Util.SequencedHashMap+Entry)-> >> > > >> > > 02e2efdc(NHibernate.Engine.Query.HQLQueryPlan)-> >> > > >> > > 02e2f1dc(System.Object[])-> >> > > >> > > 02e2f1f0(NHibernate.Hql.Classic.QueryTranslator)-> >> > > >> > > 02e2f4c4(System.Collections.Generic.List`1 >> > > >> > > [[NHibernate.SqlCommand.SqlString, NHibernate]]) >> > >> > > >> > > I checked and there was exactly 1 instance of the >> SessionFactoryImpl >> > > >> > > in the dump - checking it's size took a few hours, which is not >> > > >> > > surprising: >> > >> > > >> > > sizeof(067016bc) = 716798348 bytes >> > > >> > > (NHibernate.Impl.SessionFactoryImpl) >> > >> > > >> > > That is one big SessionFactory :-) Still tracking the >> SqlString I >> > > >> > > explored the query plan cache and ended up at the LRUMap, which >> > > >> > > according to the code is supposed to keep the last (128 in >> this case) >> > > >> > > most recently used queries in cache. The LRUMap looked like >> this: >> > >> > > >> > > Name: NHibernate.Util.LRUMap >> > > >> > > Fields: >> > > >> > > MT Field Offset Type VT Attr >> Value >> > > >> > > Name >> > > >> > > 0f76a554 4000e40 c ...ncedHashMap+Entry 0 instance >> 067030bc >> > > >> > > _sentinel >> > > >> > > 79101fe4 4000e41 10 ...ections.Hashtable 0 instance >> 067030d4 >> > > >> > > _entries >> > > >> > > 790ffcc8 4000e42 4 System.Int64 1 instance >> 104874 >> > > >> > > _modCount >> > > >> > > 79102290 4000e51 14 System.Int32 1 instance >> 128 >> > > >> > > maximumSize >> > >> > > >> > > That is, 128 max size. Examining the hashtable called Entries >> in the >> > > >> > > LRUMap revealed this though (some lines removed): >> > >> > > >> > > Name: System.Collections.Hashtable >> > > >> > > Size: 56(0x38) bytes >> > > >> > > Fields: >> > > >> > > MT Field Offset Type VT Attr >> Value >> > > >> > > Name >> > > >> > > 7912d9bc 400092b 4 ...ashtable+bucket[] 0 instance >> 0c8af170 >> > > >> > > buckets >> > > >> > > 79102290 400092c 1c System.Int32 1 instance >> 92382 >> > > >> > > count >> > > >> > > 79102290 400092d 20 System.Int32 1 instance >> 35331 >> > > >> > > occupancy >> > > >> > > 79102290 400092e 24 System.Int32 1 instance >> 112634 >> > > >> > > loadsize >> > > >> > > 79102290 4000930 2c System.Int32 1 instance >> 92391 >> > > >> > > version >> > >> > > >> > > Supposedly it contains ~90000 objects (count field) and a big >> > > >> > > (reachable) object size: >> > > >> > > sizeof(067030d4) = 716798264 bytes >> (System.Collections.Hashtable) >> > >> > > >> > > I have examined the LRUMap source and can't find any glaring >> mistakes, >> > > >> > > I looked at the LRUMapFixture, which didn't seem to contain >> any tests >> > > >> > > that verify that it actually is limited to it's max size. >> However, I >> > > >> > > made a unit test in my own test project: >> > >> > > >> > > [Test] >> > > >> > > public void LRUTest() >> > > >> > > { >> > > >> > > LRUMap map = new LRUMap(10); >> > >> > > >> > > for (int i = 0; i < 20000; i++) >> > > >> > > map.Add("str" + i, i); >> > >> > > >> > > Assert.AreEqual(10, map.Count); >> > > >> > > } >> > >> > > >> > > and this passed just fine. >> > >> > > >> > > Now this is where I am stumped, somehow my application manages >> to >> > > >> > > squeeze all these objects into the cache, but I haven't been >> able to >> > > >> > > reproduce it with simple tests. >> > >> > > >> > > Does anyone have an idea what could be the culprit? >> >> > > > -- > Davy Brion > http://davybrion.com > -- You received this message because you are subscribed to the Google Groups "nhusers" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/nhusers. For more options, visit https://groups.google.com/d/optout.
