Reputation: 337
I will preface this question with the statement that I am new to Java garbage collection, so if the collector takes care of the problem I will be happy with that. Or if I am woefully ignorant Java memory allocation, which I in fact am, I apologize. But, I am considering the following three scenarios:
public class ScenarioA implements MyQuestion{
private Field field;
public Field getField(){
if(field == null){
field = new Field(this);
}
return field;
}
vs.
public class ScenarioB implements MyQuestion{
public Field getField(){
return new Field(this);
}
}
vs.
import java.lang.ref.WeakReference;
public class ScenearioC implements MyQuestion{
private WeakReference<Field> weakField;
public Field getField(){
if(WeakField == null || weakField.get() == null){
weakField = new WeakReference(new Field(this));
}
return weakField.get();
}
}
I think that ScenarioA
is just bad, because if .get()
is ever called on an instance of ScenarioA
, we will maintain strong references between that instance of ScenarioA
and the instance of Field
returned by the .get()
method, meaning that neither will ever be garbage-collected, whether or not the program actually cares about either one.
ScenarioB
has the problem of potentially instantiating a vary large number of .equal
objects, which could be very expensive and unnecessary.
ScebarioC
I understand the least. I have tried to read the source for WeakReference
(here), but I can't figure out what's going on. I'd like to blame that on certain GC/VM opperations happening behind the scenes, but I'd like to blame a lot of things on a lot of other things. Anyway, it seems to me that every WeakReference
must require strictly more memory than simply maintaining a reference to the referent, since we must first maintain a reference to the WeakReference
, which then maintains a reference to the actual object. (My apologies for that sentence). This could be bad if Field
is large and/or we instantiate several ScenarioA
's. More importantly though, it appears to me that each WeakReference
requires its own thread, which itself (the thread) appears to never die unless the instance ScenarioC
--and thus the weak reference-- dies. This could be really bad if there are a lot of instances of ScenarioC
.
Does anyone have a solution to this problem?
Upvotes: 0
Views: 1995
Reputation: 81347
When considering the use of a WeakReference
, you should ask yourself how you would feel if they were instantly invalidated the moment that there were no strong references to the target. In most places where WeakReference
is appropriate, such behavior would be desirable; if such behavior would be undesirable in a particular situation, that's often a sign that some other form of cache would be more appropriate.
Fundamentally, WeakReference
is generally not appropriate for establishing a connection to the target object itself, but rather for establishing an indirect connection to the other things which reference the target object. When there are no other things that reference the target object, the weak reference will become useless and should be eliminated.
Consider, for example, an object Joe
whose purpose is to let anyone who's interested know how many times object Fred
does something. It asks Fred
to let it know (by calling a method) whenever it does the action in question, and each time that method is called Joe increments a counter. Under such a scenario, it would be appropriate for Fred to either hold a weak reference to Joe, or else hold a reference to something that holds a weak reference to Joe. After all, Fred doesn't care about the counter--its sole interest is ensuring that everyone that wants to know about its actions will find out about them. Fred isn't really interested in Joe per se, but rather in the fact that other entities might be interested in Joe. Once nobody else is interested in Joe, there's no reason why Fred should be.
With regard to your example, a weak reference would be appropriate if the benefits of filling future requests with the same object as earlier requests would primarily stem from the existence of other references to that object. Without knowing more about the usage patterns of the objects in question, it's impossible to say whether they would meet that description. That is, however, the issue I would focus on in deciding whether to use weak references.
Upvotes: 2
Reputation: 298579
You cannot derive the way WeakReference
works by looking at its source code. The garbage collector knows the special semantics of the WeakReference
class and treats its referent
accordingly. When you really need to use a WeakReference
you have to be aware that its get
method always can return null
as long as there is no ordinary (aka strong) reference to its referent
, even if you just checked the return value of get
right before it, and even if you just have created the WeakReference
right before it.
You have to use a strong reference, e.g. in a local variable, to hold the new instance or to check the instance returned by WeakReference.get()
before returning it:
import java.lang.ref.WeakReference;
public class ScenarioC implements MyQuestion {
private WeakReference<Field> weakField;
public Field getField() {
if(weakField!=null) {
Field field = weakField.get(); // create an ordinary strong reference
if(field!=null) return field; // the strong reference works as known
}
Field field=new Field(this); // keep the new instance ordinarily
weakField = new WeakReference<Field>(field);
return field; // return the ordinary strong reference to the new instance
}
}
Note that this code is still not thread-safe, it only shows how to handle possible garbage collection when using a WeakReference
.
Upvotes: 0
Reputation: 65889
The only recommendation I would suggest for best practices with WeakReference
is don't use them with the possible caveat of unless you really have to. They will not help with what you are trying to do.
You seem to be worried about making too many objects - this is a common mistake with newbies to Java. Making objects and releasing them is a fundamental mechanism in Java and has been tuned to be exceptionally efficient. The only consideration you need to worry about is if the object takes a lot of time to build or takes a lot of space. In that case you should consider using a pool (which may use a WeakReference
behind the scenes).
The other alternative to consider is using a Singleton
.
Upvotes: 0