Christophe Roussy
Christophe Roussy

Reputation: 16999

Why are some some resources in Java not garbage collected and must be closed or autoclosed?

If you are lucky some of these classes implement AutoClosable but sometimes you just have to be careful and inspect the existing methods to notice that there is a close, destroy or shutdown method (or what ever the author decided to name it).

This is a major source of resource leaks in Java.

I was discussing this with a colleague and wondered too: why can this not be automated in some way ?

In theory you can use finalize for such cases, but it is not recommended. So why is there no way to just use some of those closable resources and let the GC autoclose them when the instance is no longer reachable without having to remember to explicitely write some close handling code (like try ...) ?

Is this because the system may have been resource starved (File descriptors, ...) before the GC kicks in ?

NOTE: I use autoclose when possible and check my code for memory leaks using FindBugs (+ FB contrib), but still, I wonder ...

Also of interest (as discussed in the answers): deprecation of finalize.

Upvotes: 11

Views: 1849

Answers (5)

miskender
miskender

Reputation: 7938

If you are developing a common module(or a common util class), you can use execute around method pattern to handle resources that needs to be closed. So this way users of your module don't have handle these resource's closing.(Probably prevents many bugs, because people may forget to close the resource.)

There is a great presentation by Mr Venkat, that he talks about this problem. Watch the next 10 minute, he explains this beautifully.https://youtu.be/e4MT_OguDKg?t=49m48s

Here is the sample code from the presentation;

public class Resource {
    /*
     * This represents a resource that needs to be closed.
     * Since opening and closing the resource are done through use()  method,
     * Users of this resource don't have to care about resource is being closed or not.
     * They just have to pass operations that they want to execute on the resource.
     */
    private Resource() {System.out.println("created..");}
    public Resource op1() {System.out.println("op1");return this;}
    public Resource op2() {System.out.println("op2");return this;}
    private void close() {System.out.println("closed..");}

    public static void use(Consumer<Resource> consumer) {
        Resource resource = new Resource();
        try {
            consumer.accept(resource);
        }
        finally {
            resource.close();
        }
    }
}

public class SampleResourceUser {
    /*
     * This represents the user of the Resource,
     * User only cares about which operations that needs to be done on the resource.
     * Opening and closing the resource wrapped around the operation methods by the owner of the Resource.
     * 
     */
    public static void main(String[] args) {
        Resource.use(resource->resource.op1().op2());
    }
}

Upvotes: 1

maaartinus
maaartinus

Reputation: 46402

To me it looks like all the answers are missing the main point: While the GC can take care of the resource closing, it can't do it fast enough.

An example is the rather unsolved problem of memory mapped files. They mapping get cleared when they're no more references to them, but in the meantime, you may run out of file descriptors or virtual memory (this indeed can happen as it's limited to a few TB).

  • The GC gets only invoked when the heap memory is exhausted, which may be long after other resources are exhausted.
  • It's impossible to efficient collect garbage as soon as an object becomes unreachable. This would require reference counting, which is way slower than generational GC and requires some additional treatment for circular references.
  • It's impossible to efficiently collect resources in some separated GC cycles, so that resource closing works fast enough.

This is why IMHO this answer is wrong. You can handle resources this way (or using finalize or whatever), but it's not good enough.

Upvotes: 2

Bill K
Bill K

Reputation: 62769

You can create your own auto-close resource if you like, but you will need to put in a little work.

You could code a manager/factory class that keeps a weak reference to an object representing each closable object. You hand out this "Representative" facade class to clients and the client uses this representative class to access the resource (It would contain a reference to the closable and act as a delegate).

This implies that the factory starts a thread and keeps a map of:

<WeakReference<Representative>, Closable> 

that it can iterate over. If the representative has been garbage collected (the WeakReference would return a null), close the closable and remove it from the map--Anything left in the collection can also be closed on VM shutdown with a hook--This is probably the most dangerous part since a thread could still be interacting with the Closable during shutdown, but we have all the tools to manage the problem.

Your closable resource itself is never held by anything outside it's Representative and the Manager/Factory so it's behavior is predictable.

I've never seen this done--probably because it seems like a lot more work than just making an object "Closable" (and would be much easier to implement incorrectly), but I don't know why it wouldn't work.

It would be quite difficult for Java to implement this as a pattern/language feature, but by giving us the WeakReference it gives us the tools to make it possible.

Upvotes: 2

Lothar
Lothar

Reputation: 5449

The Garbage Collector's only job is to collect memory that is no longer used. Adding closing of resources will have negative effects on the performance of the Garbage Collector and is currently done by the Finalizer thread that is called by the Garbage Collector anyway in order to allow implementations to clear resources before being collected. It's worth noting that this mechanism is declared deprecated because it wasn't the best solution for this kind of thing from the start, but for the time being it's possible to implement your classes to clean themselves up before they are going to be collected.

The Finalizer (or the new mechanim in Java 9) might be extended to check if the class to be collected implements AutoClosable (an interface added with Java 1.7, so it's not that old anyway) and call it in addition to finalize. This would have a similar effect as you proposed without the need to change the behavior and the role of the Garbage Collector. Maybe that's already happening (haven't tested it myself, yet).

Upvotes: 3

Andy Turner
Andy Turner

Reputation: 140319

why this cannot be automated in some way ?

Because, in general, a class can do anything: there is no easy way for the compiler to know that something was "opened", and thus should be "closed", because Java has no strong notion of ownership of values.

Even if you have a field which is of a type that needs closing, you can't easily guarantee that it won't be returned from a getter, say, to something else which is responsible for closing it.

The only really consistent way to indicate that instances of a class need closing is by implementing the AutoCloseable interface (or Closeable, or some other interface which extends it). If you're using these, IDEs may be able to provide warnings about leaked resources; but these are going to be on a best-effort basis.

Upvotes: 2

Related Questions