Does this include your changes to ClosableThreadLocal?

Also, you probably won't see a memory leak in this fashion. We only saw that
in runs that exceeded 24 hours.

On Thu, Aug 25, 2011 at 8:40 PM, Digy <digyd...@gmail.com> wrote:

> ARGH! I should have done this long before.****
>
> When I run your test application (using  Lucene.Net 2.9.4 in trunk)  in a
> loop, I see no memory leakage.****
>
> ** **
>
>         private static void Main(string[] args)****
>
>         {****
>
>             for (int i = 0; i < 10; i++)****
>
>             {****
>
>                 Main2(null);****
>
>                 Console.WriteLine(">>> MEM: " + GC.GetTotalMemory(true));*
> ***
>
>             }****
>
>         }****
>
> ** **
>
> DIGY.****
>
> ** **
>
> *From:* Ayende Rahien [mailto:aye...@ayende.com]
> *Sent:* Thursday, August 25, 2011 10:23 AM
> *To:* Itamar Syn-Hershko
> *Cc:* Digy; lucene-net-user@lucene.apache.org
>
> *Subject:* Re: [Lucene.Net] Memory leaks****
>
> ** **
>
> Itamar,****
>
> You need to have some way of knowing that the item that you have there has
> a Close method, no?****
>
> The only method that IDisposable have is Dispose(), IsDisposing and stuff
> like that isn't part of it.****
>
> ** **
>
> The CTL need some way to close its values when it is done, but in order to
> be able to do so, we need an interface to call it.****
>
> A lot of the stuff in Lucene implements Closable, which is basically
> IDisposable****
>
> ** **
>
> On Thu, Aug 25, 2011 at 10:18 AM, Itamar Syn-Hershko <ita...@code972.com>
> wrote:****
>
> Whats wrong in putting a call to Close() in Close() ?****
>
> ** **
>
> IDisposable in itself requires explicit request from the client (and can be
> called on dtor), so it is no different from IDisposable in that regard. And
> if you are calling Close() from client code, you might just as well do the
> rest of the cleaning up there as well by calling subsequent Close()-es from
> there.****
>
> ** **
>
> The only benefit of IDisposable is for lengthy disposing (the IsDisposing
> or however thats called), and I'm pretty sure we can live without it here.
> ****
>
> ** **
>
> On Thu, Aug 25, 2011 at 10:09 AM, Ayende Rahien <aye...@ayende.com> wrote:
> ****
>
> The code looks good.****
>
> What worries me is what happen when I have an object that has CTL that
> reside inside the CTL.****
>
> That would mean that the second CTL would never be freed.****
>
> ** **
>
> Most specifically, look at FieldsReaderLocal, used in SegmentReader to hold
> a FieldsReader.****
>
> The problem is that FieldsReader itself holds a CloseableThreadLocal
> (fieldsStreamTL).****
>
> ** **
>
> Let us consider the case of a SegmentReader that is used in two threads,
> then is closed.****
>
> Its thread local variables are closed, but nothing tells the FieldsReader
> that _it_ is closed, so the fieldsStreamTL is never closed.****
>
> The valu*e *will only be cleaned when you the thread is closed, and that
> may never happen (think thread pool threads, which are almost never allowed
> to die).****
>
> ** **
>
> That is why I made the thing implement IDisposable, because you have
> multiple levels of CTL.****
>
> ** **
>
> On Wed, Aug 24, 2011 at 11:05 PM, Digy <digyd...@gmail.com> wrote:****
>
>  ****
>
> I created a new version of CloseableThreadLocal for 2.9.4g branch which
> passes unit tests and is more similar to java version.****
>
> I implemented java's "ThreadLocal" class with two different approach. One
> uses Thread.AllocateDataSlot (which is tooo slow) and the other one****
>
> uses the same technique in current implementation.****
>
> Propably It will not solve the memory-leakage problem, but It may be a
> starting point to work on.****
>
>  ****
>
> http://people.apache.org/~digy/CloseableThreadLocal.cs****
>
> http://people.apache.org/~digy/CloseableThreadLocal.java    (v 3.0.2)****
>
>  ****
>
> DIGY****
>
>  ****
>
> *From:* Ayende Rahien [mailto:aye...@ayende.com]
> *Sent:* Wednesday, August 24, 2011 4:26 PM
> *To:* Itamar Syn-Hershko
> *Cc:* lucene-net-user@lucene.apache.org; Digy****
>
>
> *Subject:* Re: [Lucene.Net] Memory leaks****
>
>  ****
>
> That make sense, and explains how it works.****
>
> Basically, there is no rooted hard reference anywhere to the values. It
> looks like the actual problem is happening when you have instances in a
> thread that is no longer used, the _values_ aren't weak references, and they
> are leaking.****
>
>  ****
>
> On Wed, Aug 24, 2011 at 3:41 PM, Itamar Syn-Hershko <ita...@code972.com>
> wrote:****
>
> I moved this to a private conversation by accident, so back on the mailing
> list now.****
>
>  ****
>
> There seem to be a fundamental difference between the original Java impl
> and Lucene.NET's, which may as well be causing the leak.****
>
>  ****
>
> In the Java version ThreadLocal is a weak reference, and a hard reference
> is persisted as well along with the thread holding it (using a synchronized
> map). This allows to easily identify stale refs - if the thread holding the
> weak ref is not alive anymore, the hard ref is removed and the GC can
> process it.****
>
>  ****
>
> In Lucene.NET's implementation only a static map of weak references is
> kept. If I read this right, unlike Java's implementation where hard
> references are kept and dereferenced  from within the ThreadLocal when the
> thread is dead, here there is nothing that will tell the GC to reclaim the
> memory referenced by the Weak ref. The Weak-Hard combination that is missing
> here is probably whats causing all this mess.****
>
>  ****
>
> Ayende's solution which uses explicit disposal is virtually the missing
> piece but in different clothing, since it requires changes to the core. If
> the .NET version was made to match Java's that probably won't be necessary.
> ****
>
>  ****
>
> Before I rewrite CloseableThreadLocal to match the Java implementation - is
> there a reason it was made this way?****
>
>  ****
>
> On Wed, Aug 24, 2011 at 10:51 AM, Ayende Rahien <aye...@ayende.com> wrote:
> ****
>
> Itamar,****
>
> Can you try writing the same code in Java and see if we get the same
> results?****
>
>  ****
>
> On Tue, Aug 23, 2011 at 8:58 PM, Itamar Syn-Hershko <ita...@code972.com>
> wrote:****
>
> How come the Java version doesn't suffer from this issue? if your answer is
> going to be due to differences with the JVM, then IDisposable may well be
> our best option here****
>
>  ****
>
> On Tue, Aug 23, 2011 at 8:51 PM, Digy <digyd...@gmail.com> wrote:****
>
> Exactly, but I couldn’t find a nice solution yet.  Any help welcomed J****
>
>  ****
>
> Btw, Can you open a new issue for this ? ****
>
> Other  people may also want to work on it.****
>
>  ****
>
> https://issues.apache.org/jira/browse/LUCENENET****
>
>  ****
>
> Thanks,****
>
>  ****
>
> DIGY****
>
>  ****
>
> *From:* Ayende Rahien [mailto:aye...@ayende.com]
> *Sent:* Tuesday, August 23, 2011 8:32 PM****
>
>
> *To:* Digy
> *Cc:* Itamar Syn-Hershko
> *Subject:* Re: [Lucene.Net] Memory leaks****
>
>  ****
>
> I think that the main issue is that you have per thread state, but no way
> of releasing this per thread state when you are closing the searcher.****
>
> On Tue, Aug 23, 2011 at 7:59 PM, Digy <digyd...@gmail.com> wrote:****
>
> Yes, IndexSearcher is expected to be thread safe. ****
>
> I am not saying, there is a misuse of it.  Instead I try to understand the
> real cause of it.  IDisposable solution seems to hide the real bug.****
>
>  ****
>
> DIGY****
>
>  ****
>
>  ****
>
> *From:* Ayende Rahien [mailto:aye...@ayende.com]
> *Sent:* Tuesday, August 23, 2011 7:48 PM
> *To:* Digy****
>
>
> *Cc:* Itamar Syn-Hershko
> *Subject:* Re: [Lucene.Net] Memory leaks****
>
>  ****
>
> Digy,****
>
> IndexSearcher is thread safe, right?****
>
> From the docs (
> http://lucene.apache.org/java/3_0_1/api/core/org/apache/lucene/search/IndexSearcher.html
> ):****
>
> *NOTE*: IndexSearcher instances are completely thread safe, meaning
> multiple threads can call any of its methods, concurrently. If your
> application requires external synchronization, you should *not* synchronize
> on the IndexSearcher instance; use your own (non-Lucene) objects instead.*
> ***
>
> The problem is that when you use an index searcher in a different thread
> then the one you close it on, you are going to leak some memory. ****
>
>  ****
>
> On Tue, Aug 23, 2011 at 7:35 PM, Digy <digyd...@gmail.com> wrote:****
>
> If I change the searching code as below, It works as expected****
>
>  ****
>
>             for (int i = 0; i < 150; i++)****
>
>             {****
>
>                 ExecuteInParallel(() =>****
>
>                     {****
>
>                         var searchers = new[]****
>
>                         {****
>
>                             new IndexSearcher(directories[0], true),****
>
>                             new IndexSearcher(directories[1], true),****
>
>                         };****
>
>  ****
>
>                         {****
>
>                             var topDocs = searchers[0].Search(new
> TermQuery(new Term("val", "test")), 15);****
>
>                             for (int j = 0; j < topDocs.totalHits; j++)***
> *
>
>                             {****
>
>                                 searchers[0].Doc(j);****
>
>                             }****
>
>                             topDocs = searchers[1].Search(new TermQuery(new
> Term("val", "test")), 15);****
>
>                             for (int j = 0; j < topDocs.totalHits; j++)***
> *
>
>                             {****
>
>                                 searchers[1].Doc(j);****
>
>                             }****
>
>                             TryAddSlot(slotsField, allSlotsFromAllThreads);
> ****
>
>                         };****
>
>  ****
>
>  ****
>
>                         foreach (var indexSearcher in searchers)****
>
>                         {****
>
>                             indexSearcher.Close();****
>
>                         }****
>
>                     });****
>
>             }****
>
>  ****
>
>  ****
>
> Since IndexSearcher is closed in the thread where caching is done.****
>
>  ****
>
> I have to think about it some more but I don’t think that adding
> IDisposables to some classes would be a good solution. It is more related to
> threading issues.****
>
>  ****
>
> Anyway, I am working on it.****
>
>  ****
>
> DIGY****
>
>  ****
>
>  ****
>
> *From:* Ayende Rahien [mailto:aye...@ayende.com]
> *Sent:* Tuesday, August 23, 2011 6:05 PM
> *To:* digy digy
> *Cc:* Itamar Syn-Hershko
> *Subject:* Re: [Lucene.Net] Memory leaks****
>
>  ****
>
> It appears that we need to use searching as well to reproduce this.****
>
> Here is another version of the program.****
>
> I apologize for the code, but I basically needed to ensure that we would
> get something resembling what we have in RavenDB, which is a multi threaded
> access pattern.****
>
>  ****
>
> On Tue, Aug 23, 2011 at 5:43 PM, digy digy <digyd...@gmail.com> wrote:****
>
> If I add ****
>
>    GC.Collect(); ****
>
> after ****
>
>    simpleAnalyzer.Close();****
>
> It outputs zeroes.  Am I missing something?****
>
>  ****
>
> DIGY****
>
>  ****
>
> On Tue, Aug 23, 2011 at 5:07 PM, Itamar Syn-Hershko <ita...@code972.com>
> wrote:****
>
> See attached.****
>
>  ****
>
> The key to this problem is multi-threading. In this sample app, some of the
> threads do not dispose of their resources properly, even though Close is
> called correctly.****
>
>  ****
>
> The suggested patch is confirmed to fix this behavior, but there may be
> other pit-falls our use cases didn't reveal.****
>
>  ****
>
> Itamar.****
>
>  ****
>
> On Tue, Aug 23, 2011 at 4:19 PM, digy digy <digyd...@gmail.com> wrote:****
>
> Hi Itamar,****
>
>  ****
>
> Can you send a simple self-contained test case showing the bug?****
>
>  ****
>
> DIGY****
>
>  ****
>
> On Tue, Aug 23, 2011 at 2:41 PM, Itamar Syn-Hershko <ita...@code972.com>
> wrote:****
>
> Hi,****
>
>  ****
>
> We recently discovered another memory leak within Lucene.NET, that is
> related to LUCENENET-358 (CloseableThreadLocal memory leak in
> LocalDataStoreSlot). As it turns out, disposables weren't disposed properly.
> With RavenDB, that caused memory consumption to always grow.****
>
>  ****
>
> We ended up modifying some core files to assure proper disposal, and things
> are looking better now. We are still testing, and will follow up if more
> fixes will be required.****
>
>  ****
>
> Here are the relevant diffs in our fork of Lucene.NET:****
>
>  ****
>
>
> https://github.com/ayende/ravendb/commit/a5031049599968f85e733f22a1ed568c09703c30
> ****
>
>
> https://github.com/ayende/ravendb/commit/bd9ca1ab154732d27985c2d237917af8bbd5fbf3
> ****
>
>  ****
>
> The full discussion and bug hunting is here:****
>
>  ****
>
>
> http://groups.google.com/group/ravendb/browse_thread/thread/9c6340987407aece/1d86d6a61175233c
> ****
>
>  ****
>
> I'm also attaching a diff between our fork to the Lucene.Net_2_9_2_RC2 tag.
> Will be happy to see this incorporated into 2.9.4 (and for it to be released
> already...).****
>
>  ****
>
> Itamar.****
>
>  ****
>
>  ****
>
>  ****
>
>  ****
>
>  ****
>
>  ****
>
>  ****
>
>  ****
>
>  ****
>
>  ****
>
> ** **
>
> ** **
>
> ** **
>

Reply via email to