Reputation: 9376
I have a general idea of how the Garbage Collector works in Java, but my reasoning for destroying an object is not because I care about freeing up memory, but because of functionality. I can explain better with an example:
Say I'm making a game where money is involved. When a person picks up a Money
object off the ground, I want to call that object's addTo
method, which involves adding a value to that person's wallet.
public class Money {
/** The value of this object. */
private final int value;
// constructor
public Money(double x) {
this.value = x;
}
// Should be called when a Person picks up this object.
public void addTo(Person bob) {
bob.addToWallet(this.value);
}
// MAIN METHOD
public static void main(String[] args) {
Person bob = new Person();
Money dollar = new Money(1.00);
dollar.addTo(bob); // bob finds $1.00
}
}
After dollar
is found, I don't want someone else to be able to pick it up. In other words, I don't want myself or any other program to be able to accidentally call the line:
dollar.addTo(alice);
So after Bob picks up the money, its value is added to his wallet and there's no need for an object representation of that value anymore. It's not that I care about the memory the object is using, but I don't want that object to be accidentally used somewhere else in the program. How do I destroy dollar
besides setting dollar = null;
?
Upvotes: 2
Views: 1051
Reputation: 3529
Though defining ownership (ground with collection of Money
s, wallet as collection, or owner attribute for money) could be theoretically cleaner solution, I can easily imagine situation when this is overkill.
For example, it could be completely irrelevant where person have taken his money. And once money have been taken the game don't care who posses that instance of Money
I suggest to simply add isPicked
attribute:
public class Money {
private final int value;
private boolean _isPicked = false;
public Money(double x) {
this.value = x;
}
public boolean isPicked(){
return _isPicked;
}
public void addTo(Person bob) {
if( this.isPicked )
throw new Exception("some message for developers");
bob.addToWallet(this.value);
_isPicked = true;
}
public static void main(String[] args) {
Person bob = new Person();
Money dollar = new Money(1.00);
dollar.addTo(bob); // bob finds $1.00
// dollar = null; // don't need this anymore
Person alice = new Person();
dollar.addTo( alice ); // <------ RUNTIME EXCEPTION
}
}
Doing dollar = null
will result in exception too, but it's less safe, because you can simply forget to do it, or accidentally copy reference to another variable
Upvotes: 0
Reputation: 18611
You have NO CONTROL over Java Garbage Collection -GC- and there is now way that you can force the Java Virtual Machine to destroy an object for you.
You can call System.gc()
[or Runtime.getRuntime().gc()
] but that only suggests the JVM to run the Garbage Collection. The true is that the JVM is not supposed to listen to you for this and the GC execution is not guaranteed. Do not rely on that.
Regarding your design need, put your money in a bank (or a street if you want people to find them) and ask the bank to give you one. Assuming that the bank has only 1, then subsequent calls will return null.
EDIT AFTER DOWNVOTE
I decided to remove some dust from my books and to quote a few lines from the Forcing Garbage Collection section of the 3rd chapter of the SCJP Study Guide. A book that I studied for pure masochism.
The first thing that should be mentioned here is that, contrary to this section's title, garbage collection cannot be forced.
..it's recommended that you never invoke System.gc() in your code - leave it to the JVM.
..it is only possible to suggest to the JVM that it performs garbage collection. However, there are no guarantees the JVM will actually remove all of the unused objects from memory (even if garbage collection is run).
Garbage Collection is a harder concept than it seems...
Upvotes: 1
Reputation: 13374
As an extension to what @pstanton said, keep collections of owned objects. Here's an elaborate way, which is useful for preventing mistaken code from corrupting your state.
public abstract class Possession {
private Object _key = null;
public synchronized Object acquire() {
if (_key != null) { throw new IllegalStateException(); }
_key = new Object();
}
public synchronized void release(Object key) {
if (_key != key) { throw new IllegalStateException(); }
_key = null;
}
}
public class Possessions implements Iterable<Possession> {
private final Map<Possession, Object> _possessions = new IdentityHashMap<...>();
public synchronized void add(Possession p) {
if (!_possessions.containsKey(p)) {
_possessions.put(p, p.acquire());
}
}
public synchronized void remove(Possession p) {
Object key = _possessions.remove(p);
if (key != null) {
p.release(key);
}
}
public Iterator<Possession> iterator() {
return Collections.unmodifiableSet(_possessions.keySet()).iterator();
}
}
public class Money extends Possession { ... }
public class Person {
private final Possessions _possessions = new Possessions();
public void add(Money money) {
_possessions.add(money);
}
}
Upvotes: 1
Reputation: 36689
You shouldn't be thinking of garbage collection at all. It is up to the JVM to determine when things can be garbage collected and 99% of the time, you won't need to consider this at all if you program responsibly.
Answer me this .. how would "the object be accidentally used somewhere else in the program"?
The answer is, it couldn't. A local reference exists until the end of your main method and no longer. Unless you store a reference to it, it cannot be referenced.
As your program grows, it might be a good idea to store a reference to it temporarily. You need to represent your concept of "the ground" with an object. Since the functionality you describe is basic, you can just use any of the built in implementations of Collection
for example List
.
List<Money> floorMoney = new LinkedList<Money>();
floorMoney.add(new Money(1.00));
and when you associate money from the floor with a Person
you would remove it from the floor.
Money dollar = floorMoney.get(0); // how you access elements may vary
floorMoney.remove(dollar);
dollar.addTo(bob);
Now, unless you store a reference to dollar
somewhere in your addTo
implementation, the Money
object will be abandoned and later GC'd.
Upvotes: 3
Reputation: 20091
dollar=null
will do the trick. By eliminating the reference to that object, the object cannot be referenced. The garbage collector is not relevant here.
Think about it this way: if you don't want someone to come to your house, you don't have to blow up your house. Just don't give them the address. Fortunately Objects can't stalk other Objects like a crazed ex-girlfriend can stalk the guy who dumped her...parking outside his work, sending texts at all hours, calling his parents...
Oh, sorry, back to your question.
If the ground is a Collection
of some sort (e.g. a List
) then removing that money from your ground collection will also keep it out of the reach of other players or rogue sentient Objects.
And if your money is also an Object
with a value, after picking the first player picks it up you could set its value to -1000, thus punishing the players who would take something that is clearly not theirs.
Upvotes: 1
Reputation: 7693
why you cannot add a boolean "picked" default = false? or create a list and remove from it?
Upvotes: 0
Reputation: 5296
You simply have to avoid making 'dollar' available to places you don't want it to go. Note that this isn't really a GC issue. For a non-GC environment (like C++) someone who somehow sees a pointer to an deleted object will crash and burn if they try accessing it.
Upvotes: 0
Reputation: 7110
If you are really trying to model the real world as closely as possible, you could add a owner attribute to the dollar, so that when you call dollar.addTo(), you will have to change the owner, the dollar only belongs to one person at any given time.
Upvotes: 3