javamemory-leakstry-with-resources

Can an optimistic try-with-resources cause a memory/resource leak over time?


Consider the following code:

try (Transport transport = session.getTransport("smtp")) {
    transport.connect();
} catch (MessagingException ignored) {}

What if, for some reason the auto-close fails? That might leave internally some file handler open (maybe not with SMTP but in general)

So is it correct to say that this code is prone to a resource/memory leak?

If the answer's yes, then what should a program do in such case?


Solution

  • The answer is 'theoretically, yes, pragmatically, no'. In the sense that:

    So is it correct to say that this code is prone to a resource/memory leak?

    If this is 'yes', then

    If the answer's yes, then what should a program do in such case?

    There is absolutely nothing you can do in this hypothetical, silly case.

    Hence why it's pragmatically speaking no.

    So how can it fail?

    The code you wrote is syntax sugar. It's the same as this:

    try {
      Transport transport = session.getTransport("smtp");
      try {
        transport.connect();
      } finally {
        try {
         transport.close();
        } catch (Throwable t) {
          if (we got here because the try block threw) {
            theExceptionThatGotUsHere.addSuppressed(t);
            throw theExceptionThatGotUsHere;
          } else {
            throw t;
          }
        }
      }
    } catch (MessagingException ignored) {}
    

    You see why java has syntax sugar for that mess. In essence, it just does the same thing we used to do, with the one upside that if close() throws an exception, java takes some pains to ensure this does not end up confuscating the exception thrown by the main body. Generally if the flow goes:

    Hence, perhaps, it's essentially as simple as:

    try {
      Transport transport = session.getTransport("smtp");
      try {
        transport.connect();
      } finally {
        transport.close();
      }
    } catch (MessagingException ignored) {}
    

    So, how can this fail? Simple: If close() itself can no longer close the resource.

    However:

    Specifically, the close() may fail, but what they won't do, is cause a resource/memory leak even if they fail. What DOES happen is the following: