2

The Java garbage collector is failing to collect dead objects in a program I wrote, and I believe this is because the dead objects have created instances of their inner classes.

When I look at the instances of the inner class in Debug mode, after the creator should have been collected, I find a reference titled this$0, which points to the should-be-dead object.

Is there a way to prevent an Outer.this reference from being created by java in each instance of Inner? This field has no use in the program, and all it does is prevent garbage collection, quickly causing the heap to run out of memory. Moving Inner out of Outer is not an option because it has public data fields that should only be visible to Outer.

blahman
  • 1,304
  • 1
  • 12
  • 18
user1123936
  • 181
  • 3
  • 4
  • 14
  • 1
    How you have validated those are not GCed? – kosa Jan 11 '12 at 01:46
  • Yeah, the this$0 that I see in Debug mode is still in memory and can be viewed. – user1123936 Jan 11 '12 at 02:00
  • Do you know for sure that the instances aren't GC'ed when you run without the debugger? Maybe they're being kept around so that the debugger can display them. I've found (running in Eclipse at least) that the garbage collector often works differently in debug mode from in run mode. – Dawood ibn Kareem Jan 11 '12 at 02:17
  • Two dead objects on the heap that form a cycle (or any number for that matter) can still be garbage collected. The following talk is a good explanation of how things work. http://www.infoq.com/presentations/Understanding-Java-Garbage-Collection – BillRobertson42 Jan 11 '12 at 02:33

3 Answers3

4

Your inner class maintains this$0 so it can get at the private fields and methods of the outer class. If your inner class does not need to use anything in the outer class, you can mark the inner class static to prevent it from maintaining a reference to an instance of the containing class.

Mike Daniels
  • 8,582
  • 2
  • 31
  • 44
  • The inner class is not static though, as I am creating many instances of it. – user1123936 Jan 11 '12 at 01:55
  • 2
    @user1123936 -- You don't understand what a static inner class is. It can have multiple instances. – Hot Licks Jan 11 '12 at 02:03
  • I'm skeptical about that. Regardless, though, I need my inner class to be non-static, because each instance of it needs to invoke non-static methods that use it's non-static instance data. – user1123936 Jan 11 '12 at 02:10
  • Then, in theory, when your Outer class gets out of scope, your Inner Class should get also, futhermore, freeing all space you need. In theory, there's nothing wrong about that, unless the Inner instances aren't dying after the Outer stance get's out of scope. Then, there's something really wrong in your design. – SHiRKiT Jan 11 '12 at 02:18
  • 1
    @user1123936, I'm not sure I've communicated properly. The inner class can be static if it uses no instance fields or methods of the **outer** class. Marking an inner class static does not have anything to do with how that inner class can use **its own** fields and methods. – Mike Daniels Jan 11 '12 at 02:23
  • I'm fairly certain that Hot Licks and Mike Daniels are correct in their interpretation of what a nested (inner) static class is. [This StackOverflow discussion](http://stackoverflow.com/questions/1353309/java-static-vs-non-static-inner-class) appears to document it, and nowhere does it imply that multiple instances of such a static class cannot exist, only that their access level will be different. Hope this might help any design issues you may encounter ^^ – blahman Jan 11 '12 at 02:24
  • @SHiRKiT, The inner classes need to survive because later generations of the outer class still use them. – user1123936 Jan 11 '12 at 03:46
  • @Mike Daniels, in that case, making the inner class static might fix everything. I'll try that. – user1123936 Jan 11 '12 at 03:46
  • Making the inner class static didn't seem to change the semantics of the program, and it removed the this$0 field that was visible in Debug mode. For some reason, calling Outer.this in expressions still calls up a live should-be-dead object, though. And I still have a heap overflow when I run. – user1123936 Jan 11 '12 at 03:59
  • @user: If `Outer.this` even **compiles** when placed within the inner class then you didn't actually make your inner class static. – Mark Peters Jan 11 '12 at 04:12
  • @Mark Peters, You're right, I must have been running bytecode that was compiled with a non-static inner class when I tested that, because I did it again just now and Outer.this can't evaluate. Anyhow, I must still have surviving references to old instances of Outer hidden somewhere, because after a short period of making new generations of Outer and replacing the originals, I still run out of heap memory. – user1123936 Jan 11 '12 at 04:20
  • @user: Have you run a memory profiler to confirm your suspicions? You might be wasting your time by assuming you know the cause. – Mark Peters Jan 11 '12 at 04:32
  • Wait a second, you want LATER instances of the Outer class to access the instances of the Inner class, even if it's not theirs (i.e. the Inner class instances belongs to another Outer class instances)? If that's the case, then using nested classes is a bad solution. You should look to package protect your classes. – SHiRKiT Jan 11 '12 at 14:13
  • @Mark Peters, Nope, I'm a newbie. I'll look into that though. – user1123936 Jan 11 '12 at 15:29
  • @SHiRKiT, I don't see anything wrong with it, as long as Outer knows how to handle instances of Inner, regardless of whether it created them. Outer can't tell whether it created it or not, and it doesn't matter in this situation. Packages seem like they are more trouble than they are worth in this case. – user1123936 Jan 11 '12 at 15:33
  • @user1123936, I disagree with SHiRKiT. It is fine for any instance of `Outer` to use any instance of `Inner` regardless of which `Outer` instance created which `Inner` instance. As an aside, packages are a fairly simple concept and if you are already working with inner classes then it will not take you long to learn how to use packages. – Mike Daniels Jan 11 '12 at 18:43
4

Regardless, though, I need my inner class to be non-static, because each instance of it needs to invoke non-static methods that use it's non-static instance data.

In that case, the outer objects shouldn't be garbage collected ... because the outer objects are where that instance data resides!


FOLLOWUP

What would you recommend then? I have no idea how use packages, but I need to create instances of Inner which have public data fields accessible only to Outer, and can survive past the destruction of Outer. Am I out of luck?

Before I answer your question:

  • "I have no idea how use packages ..." - you ought to learn about them then. Packages and "package private" access are an important part of the Java language.

Now to your question ...

If you want fields only to be accessible to the Outer class (and classes nested within) then you have to use nested or inner classes. (If you try to do this using a package and package-private access, then other classes declared in the same package can also access the fields. However, if that's acceptable, then packages are a simpler way to do this.)

Assuming that you are going to do this using nested or inner classes, then there are two ways to do this:

  • If you declare the Inner class as private static class Inner, then methods in the Inner class CANNOT call instance methods or access instance fields of Outer ... unless they have a reference to and Outer instance (e.g. passed as a parameter). If Inner is static, the lifetime of instances of Inner and Outer are independent.

  • If you declare the Inner class as private class Inner, then methods in the Inner class CAN call instance methods or access instance fields of Outer. But the flip side is that the lifetime of an Outer instance and its Inner instances are now dependent. Specifically, an Outer instance will exist as long as at least one of its Inner instances continues to exist. (The reverse is not true ... unless the Outer instance is holding references for Inner instances in (say) a collection-typed field.)

Just to restate what I said previously. If an Inner instance needs to access instance fields or call instance methods on an Outer instance, then it needs an explicit or reference to that Outer instance. That means that the Outer instance is reachable, and is not a candidate for deletion by the garbage collector.

The other point is an instance of Inner won't go away if it is still reachable; i.e. if some part of your running application has a reference to the instance that it could possibly use. In Java, objects DON'T get garbage collected if there is any possibility that they could be used by the running application. Instances of inner/nested classes are not special in this regard.


Actually, there may be a (really nasty!) way to do it break the linkage between the Inner and Outer instances. If you can find all of the Inner instances, you can use reflection to assign null to the this$0 hidden variable in each one. However, if you do that, any code in the Inner class that refers to the Outer instance state will break. If you are going to resort to this kind of nastiness, you are better off declaring Inner as a static class.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • What would you recommend then? I have no idea how use packages, but I need to create instances of Inner which have public data fields accessible only to Outer, and can survive past the destruction of Outer. Am I out of luck? – user1123936 Jan 11 '12 at 02:20
  • What do you mean by "public data fields accessible only to Outer"? Are they "public", or are they "accessible only to Outer"?. If you can clarify this, it may lead to the solution. – Dawood ibn Kareem Jan 11 '12 at 02:50
  • Inner's data fields are declared public, but they are only accessible to Outer because the class Inner is declared as private to Outer. – user1123936 Jan 11 '12 at 04:07
0

About all you can do is make the inner classes static, or not use inner classes at all.

You can, of course, make use of package scoping to limit visibility of fields in the classes without having to resort to inner classes.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151