2

I'm extremely confused about how finalizers work in the JVM regarding Garbage Collection from several sources here and around the internet.

It is my understanding, the usual approach is not to rely on finalizers to perform clean up as there's no guarantee about when they will be called or whether they would be called at all if the application finishes. However, I would still expect them to be called when the application finishes and all object cease to exist, as long as the application is alive.

In my particular case, I have an application with a class that opens a connection to another resource.

Simplified we will have

public class MyClass {

  Connection connection = new Connection();

  public MyClass() {
    connection.open();
  }

  public void close() {
    connection.close();
  }

  @Override
  protected void finalize() {
    connection.close();
  }
}

public class Main {
  public static void main(String[] args) {
    MyClass instance = new MyClass();

    // If I call instance.close(), application ends when it reaches end of main method
   // instance.close()

   // If not called, application will not end.

  }
}

Note the encapsulation purpose of "MyClass", the calling code does not necessarily need to know (nor does it need to) that he's using a non managed resource.

What happens is the application keeps running for ever, I assume hanged up on the open connection without ever releasing it since GC isn't called (and will never be called since there's no real memory pressure).

If the GC is not called when the application finishes, is there a way to guarantee the non managed resource (the connection) is closed when the application finishes? Obviously without having to explicitly call close.

I've seen the AutoClosable interface, and that is definitively an option but it still doesn't guarantee the connection will be eventually dropped when the application finishes.

Jorge Córdoba
  • 51,063
  • 11
  • 80
  • 130
  • You could register a [JVM shutdown hook](http://docs.oracle.com/javase/7/docs/technotes/guides/lang/hook-design.html) but even then, there is no guarantee that the hook is executed when the programs crashes or runs out of memory. – Mick Mnemonic Feb 06 '17 at 12:30
  • Possible duplicate of [Are resources used by a Java application freed when it terminates?](http://stackoverflow.com/questions/10906226/are-resources-used-by-a-java-application-freed-when-it-terminates) – the8472 Feb 06 '17 at 12:30
  • 3
    The GC does not run and clean up all objects when the JVM shuts down. There would be no point to clean up the Java heap, because when the process finishes the memory of the process is freed by the OS anyway. And it is not running just to run finalizers; you've correctly understood that there is no guarantee that finalizers are ever run. – Jesper Feb 06 '17 at 12:32
  • You may be interested in https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html and https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook-java.lang.Thread-... Also it depends, how you actually close the application, for example System.exit() – Balazs Vago Feb 06 '17 at 12:37

1 Answers1

2

If the GC is not called when the application finishes, is there a way to guarantee the non managed resource (the connection) is closed when the application finishes? Obviously without having to explicitly call close.

If you call (on Unix)

kill -9 {pid}

the process dies immediately without notifying the process. e.g no finally blocks are called. There is nothing you can do to prevent this.

You can enable to that finalizers are called on a graceful shutdown with runFinalizersOnExit but only on a graceful shutdown.

BTW If you pull out the power, or the network connection you won't have a graceful disconnect either, so you can't avoid needing to handle this, all you can do is cleanup on a graceful close()/shutdown.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • If you see the edited code, explicitly calling "close" will allow the application to finish when it reaches the end of the main method. However, if you do not call close, the app will instead hang in there, apparently blocked... if "MyClass" is inside a library, I would like to protect the user, at least, if they do not call close, by closing the connection when the MyClass instance can no longer be reached. Is there a way to do that? – Jorge Córdoba Feb 06 '17 at 14:10
  • @JorgeCórdoba Most likely your connection has started some non-daemon processes which is keeping your application alive. I would ensure any threads you start are daemon threads. – Peter Lawrey Feb 06 '17 at 14:14
  • 1
    @Jorge Córdoba: do you know what “*when the MyClass instance can no longer be reached*” actually means? In a non-trivial use case, where the garbage collector really runs, it might get collected while you are still using the `Connection` instance. (Using the `Connection` instance does not imply using the `MyClass` instance). See [here](http://stackoverflow.com/questions/26642153/finalize-called-on-strongly-reachable-object-in-java-8). – Holger Feb 06 '17 at 14:38
  • @Holger I don't know what that means in Java, but that doesn't make any difference to the question I'm asking. How can I ensure the connection is dispose properly once it is no longer used. Is the only method to implement AutoClosable (or a Disposable interface) and make users of the MyClass invoke the close() method?... Isn't there a way to make sure the connection is properly closed when they simply stop the app? – Jorge Córdoba Feb 06 '17 at 15:42
  • @JorgeCórdoba you can set it to run finalizers on shutdown, but you can't guarantee it will be run, the other end of the connection has to allow the possibility it won't be close gracefully. – Peter Lawrey Feb 06 '17 at 15:46
  • @JorgeCórdoba BTW Don't confuse main() returning with the program shutting down. Either can happen without the other. – Peter Lawrey Feb 06 '17 at 15:47
  • @JorgeCórdoba if the problem is as I said, you have a non-daemon thread running, your program won't shutdown because that's what a non-daemon thread is supposed to do. – Peter Lawrey Feb 06 '17 at 15:48
  • @PeterLawrey I have no control over the "connection" object. If it is creating a non-daemon process, then it is. That is precisely the reason for wanting a finalizer or a destructor, to orderly close that connection when the class is no longer in use. I was looking for something like the "destructor" + "IDisposable" pattern that you have in .NET but in Java https://msdn.microsoft.com/en-us/library/system.object.finalize(v=vs.110).aspx – Jorge Córdoba Feb 06 '17 at 15:49
  • 1
    @PeterLawrey I think I see what you mean. Calling System.exit(0) may run the finalizers if "runFinalizersOnExit" is set up, allowing controlled shutdown or just hard stop it... I was indeed identifying control reaching the end of the main method with the application shutting down. – Jorge Córdoba Feb 06 '17 at 15:54
  • @JorgeCórdoba The whole point of having a non-daemon thread is that you want the application to keep running if it is running. If you want a workaround for what appears to be a bug in the library, you can do it but it's not going to be reliable. – Peter Lawrey Feb 06 '17 at 15:56
  • 1
    @Jorge Córdoba: think again. You asked “*How can I ensure the connection is dispose properly once it is no longer used*” and the answer is “*by explicitly telling that it will no longer be used*”, e.g. calling the close method. The lifetime of the `MyClass` instance is irrelevant to this task. It might be far longer than you think, but it might be *even far shorter* than you think. The reason why `runFinalizersOnExit` is deprecated is much similar. Read [its documentation](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#runFinalizersOnExit-boolean-)… – Holger Feb 06 '17 at 16:07