cayenne-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrus Adamchik <and...@objectstyle.org>
Subject Re: Watch out for memory leaks with EhCache
Date Sun, 08 Dec 2019 09:16:38 GMT
Hi John,

Thanks for the analysis. You've put a significant effort in this issue, but I still feel like
we have differences in understanding of the causes (and hence the remedies). Let me try to
clarify how I see it.

> On Dec 7, 2019, at 12:09 AM, John Huss <johnthuss@gmail.com> wrote:
> 
> 1) The lifetime of entries in the Local Query Cache exceeds their
> availability, which is the life of their ObjectContext. Any cache that is
> not expiring entries (or limiting them) will just leak this memory.

A properly configured cache will "overcommit" memory, but not "leak" (i.e. it won't expand
indefinitely). Misconfigured cache was the cause of the the issue in the parent message. Once
I added upper limits on the number of entries to all cache groups, the leak disappeared. 

> 2) Cached query results will retain the ObjectContext they were fetched
> into, which in turn may retain a much larger number of objects than
> intended. For example. If you use a single ObjectContext to fetch 1 million
> uncached objects along with 1 cached object, you will retain 1 million and
> 1 objects in memory rather than just 1.

This doesn't look right. Objects are stored via weak references by the OC, so if there are
no other references to them, they will be GC'd even if the context is still around. I wrote
a self-contained test project [1] that proves this assumption [2]. If you see unexpected extra
objects cached, they are likely retained via prefetched / faulted relationships from the explicitly
cached objects (see "testWeakReferences_ToOneRelationships" test in [2]).

> This is potentially an issue with both the Shared and Local Query Caches.

Shared cache stores snapshots that do not have references to the ObjectContext. So it can't
be an issue there.

> Also, because the cached objects still reference the ObjectContext, it
> appears that the context will not be garbage collected.

Correct.

> Possible Solutions:
> 
> One solution is to null out the ObjectContext on any objects that are
> inserted into the Query Cache. This solves both problems above, and it
> seems logical since when the objects are retrieved from the cache they will
> be placed into a new context anyway. This should work, but the
> implementation has been tricky.

This will not work at the framework level, as Cayenne doesn't know who else beside the cache
references cached objects. So you'd be breaking the state of the object while it is still
exposed to the world.

> What Now?
> 
> I've taken a first stab at implementing both of these solutions and have
> had some concerns raised about each of them [1] [2]. I'd like to implement
> something to fix this problem directly in Cayenne rather than fixing it
> only for myself. I'd love to hear any feedback or suggestions on this
> before I go further down what might be the wrong road.

I happen to agree the the cache model needs improvement to be more transparent and easy to
use. But I'd like to establish some common ground in understanding the problems before we
can discuss solutions. So to reiterate what I said in reply to items 1 and 2:

* Is there a difference in terminology of what a "leak" is? Do you view it as just an overuse
of memory but with a fixed upper boundary, or do you see it as a constant expansion that eventually
leads to the app running out of memory no matter how much memory it had? 

* Objects are stored in the context via weak references, so if they are not directly cached,
they can be GC'd, even if their context is retained. Do you observe a behavior that contradicts
this?

* Shared cache can not be the cause of ObjectContext retention. Again, do you observe a behavior
that contradicts this?

Andrus

[1] https://github.com/andrus/cache-test/
[2] https://github.com/andrus/cache-test/blob/master/src/test/java/com/foo/ApplicationTest.java



Mime
View raw message