48

Has anyone researched the runtime costs involved in creating and garbage collecting Java WeakReference objects? Are there any performance issues (e.g. contention) for multi-threaded applications?

EDIT: Obviously the actual answer(s) will be JVM dependent, but general observations are also welcome.

EDIT 2: If anyone has done some benchmarking of the performance, or can point to some benchmarking results, that would be ideal. (Sorry, but the bounty has expired ...)

keelar
  • 5,814
  • 7
  • 40
  • 79
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Obviously this will depend on the JDK implementation, Sun vs IBM vs JRockit etc. – David Plumpton Aug 09 '09 at 04:07
  • 4
    Start of an answer in an article by [Goetz](http://www.ibm.com/developerworks/java/library/j-jtp01246/index.html): *At each garbage collection, a list of live Reference objects must be constructed, and each reference must be processed appropriately, which adds some per-Reference overhead to each collection regardless of whether the referent is being collected at that time. Reference objects themselves are subject to garbage collection and can be collected before the referent, in which case they are not enqueued.* – assylias Jan 27 '13 at 10:46

3 Answers3

13

WeakReferences have negative impact on CMS garbage collector. As far as I can see from behavior of our server it influences parallel remark phase time. During this phase all app threads are stopped so it's extremely undesirable thing. So you need to be careful with WeakReferences.

Vitaly
  • 1,081
  • 2
  • 9
  • 14
  • Sorry for this, but I'm trying to figure out the reasons of such behavior on Sun forums now :) – Vitaly Aug 17 '09 at 10:59
  • 2
    Vitaly, do you have anymore on this now? If you found some information on Sun forums could you post a link? Thanks! – Owen Jul 06 '10 at 19:12
  • What sort of impact do they have, obviously there is a cost,as gc needs to special case weak references etc. – mP. Jan 29 '11 at 09:49
8

I implemented a Java garbage collector once, so whatever I was able to accomplish is a (weak :) lower bound on what is possible.

In my implementation, there is a small constant amount of additional overhead for each weak reference when it is visited during garbage collection.

So the upshot is: I wouldn't worry about it, it's not a big problem unless you are using zillions of weak references.

Most importantly, the cost is proportional to the number of weak references in existence, not the size of the overall heap.

However, that's not to say that a garbage collector that supports weak references will be as fast as one that does not. The presumed question here is, given that Java supports weak references, what is the incremental cost of using them?

Mine was a simple "stop the world" mark/sweep garbage collector. During garbage collection, it makes a determination for every object whether that object is live or not and sets a LIVE bit in the object header. Then it goes through and frees all the non-live objects.

To handle weak references you just add the following:

  • Ignore weak references when setting LIVE bits (i.e., they don't cause the LIVE bit on the referenced object to be set).
  • During the sweep step, add a special check as follows: if the object you're visiting is LIVE, and it's a WeakReference, then check the object that it weakly references, and if that object is not LIVE, clear the reference.

Small variations of this logic work for soft and phantom references.

Implementation is here if you're really curious.

Archie
  • 4,959
  • 1
  • 30
  • 36
  • 1
    This is very interesting. (I think that the HotSpot implementation is different though.) How do you handle the case where a finalize method relinks the referenced object? Wouldn't that need to trigger a (partial) re-mark? – Stephen C Jul 10 '15 at 22:48
  • I'm 100% certain that HotSpot's implementation is not only different but vastly more sophisticated :) Re: finalize, that's just an extra step for non-LIVE objects.Instead of "it goes through and frees all the non-live objects" it should really say "it goes through and enqueues for finalization all the non-live objects". – Archie Jul 11 '15 at 15:15
  • Re: finalization, you have to set a bit in the object header that indicates whether `finalize()` has been invoked or not, so you don't do it twice as required. So actually non-`LIVE` object are enqueued for finalization if the bit is not set, or freed immediately if the bit is set. – Archie Jul 11 '15 at 15:17
3

cache using weak references may significantly slow down your app if it's rebuild on demand e.g. in getters:

public Object getSomethingExpensiveToFind() {
    if(cache.contains(EXPENSIVE_OBJ_KEY)) {
        return cache.get(EXPENSIVE_OBJ_KEY);
    }

    Object sth = obtainSomethingExpensiveToFind(); // computationally expensive
    cache.put(EXPENSIVE_OBJ_KEY, sth);
    return sth;
} 

imagine this scenario:

1) app is running low on memory

2) GC cleans weak references, thus cache is cleared too

3) app continues, a lot of methods like getSomethingExpensiveToFind() are invoked and rebuild the cache

4) app is running low on memory again

5) GC cleans wear references, clears cache

6) app continues, a lot of methods like getSomethingExpensiveToFind() are invoked and rebuild the cache again

7) and so on...

I came upon such problem - the app was interrupted by GC very often and it compeletly defeated the whole point of caching.

In other words, if improperly managed, weak references can slow down your application.

mantrid
  • 2,830
  • 21
  • 18
  • 1
    This doesn't answer the question I asked. You are basically saying that unwise use of weak references can be bad for performance ... due to object cache thrashing. But the question is about the overheads of the weak references themselves. (Ideally, I'd like an answer that gives some actual measurements for those overheads, but I'd also settle for an *authoritative* explanation of how they are incurred.) – Stephen C Feb 03 '13 at 08:11
  • then you should have asked about *metrics* and *benchmarks* specifically – mantrid Feb 04 '13 at 12:29
  • I did. In the bonus notice. Did you read that? But anyway, your Answer is clearly not relevant to the Question as asked. – Stephen C Feb 05 '13 at 00:27
  • This was still a useful observation, and not irrelevant to the discussion. – Will Jun 11 '13 at 07:20
  • @Will - this is not a discussion forum. It is a Q&A site. It I had wanted to initiate a discussion, I would be asking on a different site. If I had wanted to ask if using references was a good thing ... I would have asked a different question. – Stephen C Jul 10 '15 at 22:50