Yuki Hashimoto
Yuki Hashimoto

Reputation: 1073

The behavior of "Mark & Sweep" in Java, especially for Future object

I'm wondering the lifetime of Future object, which is not bound to a named variable.

I learned that Java adopts mark & sweep style garbage collection. In that case, any un-named object can be immediately deleted from heap. So I'm wondering if the Future might be swept out from memory even before the Runnable completes, or the memory might never be released.

Any information would be helpful, thanks!

class Main {
  void main() {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(() -> { return true; }); // not bind to variable
    Thread.sleep(1000);
  }
}

Upvotes: 1

Views: 415

Answers (2)

Stephen C
Stephen C

Reputation: 718826

I learned that Java adopts mark & sweep style garbage collection.

That is mostly incorrect. Most modern Java garbage collectors are NOT mark & sweep. They are mostly copying collectors that work by evacuating (copying) objects to a "to" space as they are marked. And most Java garbage collectors are also generational.

There is a lot of material published by Oracle about the Java garbage collectors and how they work. And there a good textbooks on the subject too.

In that case, any un-named object can be immediately deleted from heap.

Names have nothing to do with it. References are not names, and neither are variables. Java objects are deleted by the GC only if it finds that they are unreachable; i.e. if no code will never be able to find them again1. Furthermore they are not deleted immediately, or even (necessarily) at the next GC run.

So I'm wondering if the Future might be swept out from memory even before the Runnable completes, or the memory might never be released.

(That's a Callable rather than a Runnable. A Runnable doesn't return anything.)

The answer is no it won't.

The life cycle is something like this:

  1. You call submit passing a Callable.
  2. A CompletableFuture is created.
  3. The CompletableFuture and the Callable are added to the executor's queue.
  4. The CompletableFuture is returned to the caller. (In your case, the caller throws it away.)
  5. At a later point, a worker thread takes the Future and the Callable from the queue, executes the Callable.
  6. Then the worker thread calls complete on the Future to provide the result.
  7. Finally, something will typically call Future.get to obtain the result. (But not in your example.)

In order for the step 6. to work, the CompletableFuture must still be reachable. It won't be thrown away until all references are lost or discarded. Certainly not until after step 6 has completed.


Bottom line: a Java handles the Future just like it would any other (normal) object. Don't worry about it. If anything needs it, it won't disappear.


1 - Reachability is a bit more complicated when you consider, finalization and Reference types. But the same general principal applies. If any code could still see an object, it won't be deleted.

Upvotes: 2

Andreas
Andreas

Reputation: 159106

"Submit" means to give something to someone, in this case you're giving a piece of code (in the form of a Callable) to the ExecutorService for later execution. In return, the method returns a Future object that will be updated with the result when it is done.

In order for the ExecutorService to update the Future object, it needs to hold on the Future object too, together with the code reference (the Callable).

Therefore, the ExecutorService maintains references to both the Callable object and the Future object until the job has been completed. Those references makes both objects reachable, preventing the objects from being garbage-collected.

Since your code discarded the returned Future object, the object will become eligible for GC as soon as the job completes, but not before that.

Upvotes: 1

Related Questions