11

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.

Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
  • Mainly because the GC can be dumb and fast if it just needs to release giant blocks of coalesced memory. These resources need code to be run to do the releasing. – Lou Franco Feb 20 '18 at 16:25
  • Closing might have to perform some additional tasks, think of closing network connections. That involves a delay. You never want anything to delay the garbage collection. That's why any closing mechanism is not part of the GC cycle. – f1sh Feb 20 '18 at 16:26
  • @Lou Franco So you mean it would produce pauses and unpredictable performance in general ? – Christophe Roussy Feb 20 '18 at 16:26
  • "let the GC autoclose them when the instance is no longer reachable" it does. FileOutputStreams, for example, are closed when they are GC'd. You just can't rely upon this happening at any particular time. – Andy Turner Feb 20 '18 at 16:27
  • Or worse -- there is no way to enforce that the function returns at all. – Lou Franco Feb 20 '18 at 16:28
  • But still could it not be done via some parallel mechanism similar to GC ? It seems very old school like manual memory deallocation (calloc ...). – Christophe Roussy Feb 20 '18 at 16:28
  • I understand that manual closing is best, but when will the JVM or OS reclaim theses resources, never ? – Christophe Roussy Feb 20 '18 at 16:29
  • @ChristopheRoussy When done in the GC, yes. A full GC-run comes with a freeze of the VM, so your process essentially stops, not responding to anything except a kill-signal). `finalize` is different because it's done by a distinct thread (The Finalizer thread) not impacting the GC. – Lothar Feb 20 '18 at 16:29
  • "when" either immediately, later, or never. You can't rely on it happening at any particular time. – Andy Turner Feb 20 '18 at 16:29
  • @AndyTurner is right, you usually want very predictable releases for these -- that's what try-with-resources is for -- it's fairly automatic (not GC, but not the same as manual) – Lou Franco Feb 20 '18 at 16:30
  • 1
    Possible duplicate of [What is a resource in java?why we have to close it after it is used?](https://stackoverflow.com/questions/24854927/what-is-a-resource-in-javawhy-we-have-to-close-it-after-it-is-used) – the8472 Feb 20 '18 at 19:13

5 Answers5

3

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).

Lothar
  • 5,323
  • 1
  • 11
  • 27
  • What if you are not closing a wrapper `AutoClosable` intentionally, because you want to continue using the underlying resource? Think of `Scanner` wrapping `System.in`. You should not close the `Scanner` as that would close your standard input. Having the garbage collector/finalizer automatically closing everything that implements `AutoClosable` would be horrible. It would also open [this can of worms](https://stackoverflow.com/questions/48889746/why-are-some-some-resources-in-java-not-garbage-collected-and-must-be-closed-or#comment84863132_48890400)… – Holger Apr 13 '18 at 11:42
2

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.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • Yes some modern code uses AutoClosable, but still many classes I have seen did not. So you just have to read a lot of docs and be careful and look for names like `close`, `shutdown`, `destroy`, ... I personally use FindBugs + contrib detection, which helps a little, but I never feel safe from these. – Christophe Roussy Feb 20 '18 at 16:38
  • So it seems, this is some kind of issue on the part of Java, you can use resources, but the system does not really track the usage of resource, contrary to the usage of memory (which was a big step forward from C/C++ in many ways). Maybe more will be done in the future, hopefully more libs will implement AutoCloseable. – Christophe Roussy Feb 20 '18 at 16:43
  • There is nothing that can be done for old code that doesn't understand new mechanisms. Even if we added what you wanted to the GC, old code would not play nice with it (how would the GC know to call it?) – Lou Franco Feb 20 '18 at 16:51
  • I don't agree that it's not possible to make the resource behave predictably--It could be done. Wrote up an answer with more details. If it's not clear I could write up an example.... – Bill K Feb 20 '18 at 17:15
  • @BillK your answer still relies upon the person using a class either to know that it needs to be closed; if you applied this just everywhere in your code, it would become seriously cluttered. – Andy Turner Feb 20 '18 at 17:22
  • @AndyTurner Kind of--there are two uses. 1) a library COULD use it to auto-close itself in a safe way with no clutter that is invisible to the library user, 2) a library user user could patch a library that doesn't auto-close correctly. The only more comprehensive solution would be language-level which leads into the issues you mentioned. Also I would NOT distribute this throughout my code! Gah! I'd create a single manager class and a wrapper for each resource--everything else would look pretty much like it does now. – Bill K Feb 20 '18 at 17:55
2

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.

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • It seems there could be some solutions, but the whole Java community is not really evaluating them. Big work on GC, but for other resources, mostly manual work and good luck with some libs used in other libs, leaking ... AutoClosable is also not enforced, so we just have to pray that some lib authors uses it and that the devs also use it. – Christophe Roussy Feb 20 '18 at 17:06
  • @ChristopheRoussy it's very difficult to do at a "Java" level (For the language creators), but I thought your original question was why can't it be done by the coder? It can. You can wrap any library you want to use this way, you are not at the mercy of any language or library author, this doesn't need any additional support, you just code it up yourself for your application. Isn't that what you were asking for? – Bill K Feb 20 '18 at 17:46
  • Also any library author COULD implement their library this way but, as I said, it's a lot of work when you could just implement Closable and let the coder take care of it for you. – Bill K Feb 20 '18 at 17:51
  • 1
    I don't think your solution would really work. At the time your `Representative`s get collected, it may be too late, see [my answer](https://stackoverflow.com/a/48914782/581205). – maaartinus Feb 21 '18 at 20:22
  • 1
    @maaartinus I agree, if you have a limited resource then a closable is really the only way--you must control it's usage by code. If there is simply a class that needs a little cleanup though, this would probably work fine. Although I think it would pick up most dropped objects almost instantly, your point is that you can't rely on it if you NEED them recovered immediately--in that case closable is probably the only way to go. – Bill K Feb 21 '18 at 20:52
  • 1
    @maaartinus even worse, the object can get collected *too early*. That’s exactly what happened in [this question](https://stackoverflow.com/q/26642153/2711488). The general problem of this approach is that the front-end is not needed for the actual operation that happens in the backend object, hence, the front-end can get collected while an operation is ongoing. In principle, even the backend object can get collected with aggressively optimizing JVMs, as the memory manager only cares about the object’s memory, not whether its contained values (`long`s usually) actually represent a resource… – Holger Feb 22 '18 at 13:19
2

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.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • Good point although I don't think my answer was "Wrong", you are correct in pointing out that there are many use cases where nothing but closable style will work. – Bill K Feb 21 '18 at 20:53
  • I think all those answers are way more interesting than most stuff I have seen on SO lately. – Christophe Roussy Feb 26 '18 at 08:28
1

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());
    }
}
miskender
  • 7,460
  • 1
  • 19
  • 23