1

I'm working on a dueling system for a game that I've been working on, here's the skeleton of the class:

public class Duel {

    private Champion challenger;
    private Champion defendant;

    private boolean duelStarted;

    private long timer;

    public Duel(Champion challenger, Champion defendant) {..

    public void tick() {..

    public void declineDuel() {..

    public void endDuel(ResultType resultType, Champion winner, Champion forfeit) {..

    public void declareWinner(Champion player) {..

    public void declareForfeit(Champion player) {..

    private enum ResultType {..

    public Champion getChallenger() {..

    public Champion getDefendant() {..
}

This class will be assigned to the Champion's class for both the challenger, and the defendant.

When a duel ends (Effectively by calling Duel#declineDuel() or Duel#endDuel(ResultType, Champion, Champion) or due to something like a Champion#Disconnect(), how should I properly set the class up to be collected by the Java garbage collection.

I've never completely understood this, would I need to set everything inside of the class to null, as-well as the Duel currentDuel; declaration in Champion.class or should I only set the currentDuel to equal null, which will effectively stop referencing ( I would assume, this is what I'm confused about ) to this instance of the class.

I'm don't quite understand what the garbage collection would consider a "Referenced" class, would Duel#getChallenger() being set make it be considered referenced still, even though it's not being touched from an outside class?

I guess I'm confused between in-bound and out-bound references, would anybody care to shed some enlightenment since I can't seem to understand what's going on when i rtfm.

Hobbyist
  • 15,888
  • 9
  • 46
  • 98

2 Answers2

8

how should I properly set the class up to be collected by the Java garbage collection.

You may not need to do anything. If there are no references to the Duel from elsewhere, then the Duel object itself is eligible for garbage collection... and if the Duel is the last thing that refers to the relevant Champion objects (etc) then those will be eligible for garbage collection too.

If Champion refers to Duel via a currentDuel field (as it sounds like it does) then if you've got a separate reference to the champions (e.g. you've got a list of champions somewhere) then those champions will prevent the Duel from being garbage collected, until currentDuel is set to a different value. But really, you should be thinking in terms of what's logically useful rather than worrying about garbage collection... presumably once the duel is completed, it makes sense to set currentDuel to null anyway, as the champions are no longer fighting that duel... and at that point, they won't be keeping the Duel alive any more. It's very unlikely that you need to change anything in Duel itself though.

If the champions themselves are eligible for garbage collection anyway, then you don't need to worry about the cycle of references between Duel and Champion - that won't prevent garbage collection.

The principle in all of this is the question of "Can I still reach the relevant object through any code path from any live thread?" If you can't, then it will be eligible for garbage collection. If you can reach the relevant object, then it won't be garbage collected.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks for the clarification, is there by chance any Handlers for the garbage collector that allow us to print the objects being collected? I'm pretty sure I understand the general concept, but I'd like to watch it with different results just to make sure if at all possible. – Hobbyist Nov 16 '14 at 08:46
  • 1
    @Christian.tucker: No - at least, not in regular Java. (There may be something if you're running with a debugger agent attached.) You could add finalizers, but that in itself will change the behaviour slightly (in terms of things taking longer to be garbage collected). – Jon Skeet Nov 16 '14 at 08:47
  • 1
    @Christian.tucker There is a couple of ways of doing this however the simplest is to override the finalize() method (only do this for diagnostic purpose, if at all as it's not something you want to use any more than you have to) – Peter Lawrey Nov 16 '14 at 08:47
  • Thanks, I won't mind things taking longer to be collected while I'm just experimenting for educational purposes. – Hobbyist Nov 16 '14 at 08:49
  • @Christian.tucker it's not about how long it takes, for the reason not to use finalize for anything else see http://stackoverflow.com/questions/2506488/when-is-the-finalize-method-called-in-java – weston Nov 16 '14 at 08:53
  • @Christian.tucker finalize() is suitable for education purposes, but avoid using it at other times, used too much and it can lead to a program failing to clean up memory fast enough esp if it is writing to the console for example. BTW There is two other ways, ReferenceQueues (standard) and Cleaners (non-standard) – Peter Lawrey Nov 16 '14 at 08:54
  • Using the finalize() method I feel like I completely understand how this works now after running quite a few tests, my only other question is, should I call `System#gc()` manually when I know there's garbage to be collected, or should I leave it alone and let it collect itself automatically. – Hobbyist Nov 16 '14 at 09:04
  • 2
    @Christian.tucker: You should leave it alone in almost all cases. – Jon Skeet Nov 16 '14 at 09:04
  • @Christian.tucker The key to the efficiency of GC is that it does not care about the garbage. Instead, it collects and the surviving objects and copies them elsewhere, making all what remains to free memory. As most newly allocated objects are garbage, this reduces the overhead a lot. By using finalizers, you slow it down substantially. Usually, the best way to deal with GC is to simply trust in it doing everything right. – maaartinus Nov 16 '14 at 17:03
5

As Jon Skeet notes, the best thing to do is for your reference to your object to fall out of scope when you have finished with it. Not only does this mean you don't need to set it to null but your application will be structured in a more logical and easier to maintain way.


You only need to set the top of the object graph to be null. Once an object is no longer strongly reachable it can be cleaned up and anything it points to which is not strongly reachable can be cleaned up to.

In the case above the simplest thing might be to discard the Duel object itself and everything can be cleaned up.

If you suspect you have a memory leak, you can use your memory profiler to see which reference is holding onto an object. This tells you which reference is holding onto the object. In Java a high percentage of memory leaks are due to the object being added to a collection but not removed from the collection.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    More likely, just let the relevant variable fall out of scope. I very rarely need to set things to null for the sake of the garbage collector. – Jon Skeet Nov 16 '14 at 08:44
  • " In Java a high percentage of memory leaks are due to the object being added to a collection but not removed from the collection. " Isn't this the case for most applications of any type, that are written in any language? I see this all the time, data being smashed into a List<> or Dictionary<> or a custom implementation(depending on the language) and they're never going through and removing what's not being used anymore. – Hobbyist Nov 16 '14 at 08:48
  • 2
    @Christian.tucker in systems where memory is not managed, you have to reliably call free()/delete when you are finished with the object. This has some benefits but easily leads to bugs. A memory leak in a C/C++ program is when memory cannot ever be reclaimed, in Java that is not possible and so we give "memory leak" a different meaning in Java to refer to any object which is held on long after it is not needed. – Peter Lawrey Nov 16 '14 at 08:52
  • @PeterLawrey - That's interesting, I've never known of the C/C++ definition of a memory leak, however it makes sense. Once the memory cannot be reclaimed, it also in parallel can never be erased, correct? (Atleast from within the application) – Hobbyist Nov 16 '14 at 09:00
  • 1
    @Christian.tucker Memory is reclaimed when the application dies. Many organisations have a policy of a planned restart of software everyday so these problems don't accumulate (and it's cheaper than solving these problems which takes time) – Peter Lawrey Nov 16 '14 at 09:04