Do threads get automatically garbage collected after run() method exits in Java? - java

Does a thread self-delete and get garbage collected after it runs or does it continue to exist and consume memory even after the run() method is complete?
For example:
Class A{
public void somemethod()
{
while(true)
new ThreadClass().start();
}
public class ThreadClass extends Thread{
public ThreadClass()
{}
#Override
public void run() {......}
}
}
I want to clarify whether this thread will be automatically removed from memory, or does it need to be done explicitly.

This will happen automatically i.e. memory will be released automatically once the thread is done with its run method.

Threads only exist until the end of their run method, after that they are made eligible for garbage collection.
If you require a solution where memory is at a premium, you might want to consider an ExecutorService. This will handle the threads for you and allow you to concentrate on the logic rather than handling the threads and the memory.

Threads are automagically garbage collected on completion of the run method, hence you do not have to do it explicitly.

Threads will be garbage collected after their run method has completed. The notable exception to this is when you are using the android debugger. The android debugger will prevent garbage collection on objects that it is aware of, which includes threads that have finished running.
Why do threads leak on Android?

Related

How does gc method work?

public class GarbageC {
public void finalize()
{
System.out.println("Finalize method");
}
public static void main(String[] args) {
GarbageC c1=new GarbageC();
GarbageC c2=new GarbageC();
c1=null;
c2=null;
System.gc();
System.out.println("abc");
}
}
While I'm debugging this code, the o/p is coming as
Finalize method
Finalize method
abc
and when I run, I get this
abc
Finalize method
Finalize method
Why am I getting different outputs in both the cases
Calling System.gc() is a request. The runtime doesn't have to do collect garbage in response. It may full well decide to ignore you. As such, you can't depend on it doing the same thing consistently.
Chances are, in debug mode it really does cause a garbage collection to be run. In non-debug mode it either just doesn't collect the garbage or waits until an opportune moment to do so.
If you run it often enough you could get any of the 3 possible outputs.
The garbage collection process possibly runs in a dedicated thread (at least in any recent VM it will), so the output depends on the speed of each thread (your main thread and the GC thread of the VM).
In debug mode, the main thread is significantly slower (you may pause it indefinetly when stepping through the code). Thus the GC overtakes your main thread. When you simply run the program; the main thread will most likely run through to completeion before the VM even attempts to garbage collect.
A call to System.gc() is only a request "hey please do a gc", even if the VM honors it (its not required to), your request will be passed to the GC thread; that involves at least a slight delay before the GC will actually begin work; and some more time until it actually discovers your garbage objects and then finally collects them.

garbage collector not working?

my JDK version is 1.7.0_25
class A {
public void finalize() {
System.out.println("deleting...");
}
}
public class Test {
public static void main(String[] args) {
new A();
System.gc();
System.out.println("main class");
}
}
i expected the out put as
deleting...
main class
but in my case there were no output what is the reason ? and when i compile and run the code online with JDK 1.7.0_09 then the outputs are ,
main class
deleting...
why the "main class" prints first ?
The GC never guarantees when the the clean up happens,
finalize()
may be or may not be called.
By doin System.gc(); you are only requesting the GC to be invoked but its up to the JVM to fulfill your request.
Will the System.gc() invoke the cleanup?
The answer varies depending on lots of factors, like which JVM you're running on, which mode it's in, and which garbage collection algorithm it's using.
I wouldn't depend on it in your code. If the JVM is about to throw an OutOfMemoryError, calling System.gc() won't stop it, because the garbage collector will attempt to free as much as it can before it goes to that extreme.
So... if there is anything that you would want to perform for certain, do not write that code in finalize()
There is no guarantee whether finalize() method will be called or not when you call System.gc() method. Go throgh java API. And for the second question , main() method is a thread. And when you call garbage collector , it will be executed in another thread.So if you understand threads , by now you will know the answer (You can't predict thread execution order)
It is not specified when finalization will happen. The only thing that is specified / guaranteed is that finalization will happen before a finalizable object is actually deleted from the heap.
In practice, finalization is typically done by a special finalization thread that gets notified when the main GC thread finishes its work. It looks like control is returning to the main thread before the finalization thread gets to process the object.
Basically, you cannot rely on the order in which these things happen. And that is one of the reasons why depending on finalization to do things is generally a bad idea.
And besides, it is not even guaranteed that the System.gc() call will do anything.
In short, what you are observing is "within the envelope" of specified behaviour for finalization. The garbage collector is working. It is your expectations that are incorrect.
The other answers corrrectly stated that there is no way to make sure finalizers are run. I just wnated to add something concerning the question about the execution-order:
When a GC detects an object with a finalize()-method is to be deleted it doesn't delete it right away but first puts it on the finalization-queue. After that GC is finished and the application resumes working the VM will start running all queued finalizers - that should explain the order of your output. Only after that can the object actually be GCed.

is there any way to confirm if the thread is killed at the end of execution?

is there any way to confirm if the thread is killed at the end of execution? If the garbage collector takes long time to destroy the threads even when they are available for GC, out of memory exceptions may arise. to get rid of those kind of issues, it would be good to know if the threads have been destroyed.
As of now, my understanding is that at the end of run method , the thread gets killed and we need not do anything explicitly to kill the thread instance.
Thanks in advance!
class A
{
public static void main()
{
Thread t = new Thread(new TestA());
t.start();
Thread t1 = new Thread(new TestB());
t1.start();
Thread t2 = new Thread(new TestC());
t2.start();
}
}
class TestA implements Runnable {
Thread t;
public void run() {
for(...){
try{
}catch()
{
....
}
}
}
}
You are absolutely right that "at the end of run method, the thread gets killed and we need not do anything explicitly to kill the thread instance". Simply letting the thread leave its run() method normally is enough.
If you want to make sure that a particular thread has terminated, then Thread.isAlive() will check, and Thread.join() will wait until it happens. If you have a particular set of threads that you're worried about, then keep a reference to them somewhere, and check up on them using these methods.
Thread.getAllStackTraces()
gets you a current map of threads/stacktraces. However I would normally expect the JVM to clear up the threads upon exit from run(). Obviously if you're using some sort of thread pooling then that's not the case.
You can use some softwares like visualvm to monitor the thread states .
These kind of softwares will give you full flexibility to profile your application in a visual way.
To check the state of a thread , you can call the getState() method on a thread object to see the state of the thread.
The javadoc of OutOfMemoryError says:
Thrown when the Java Virtual Machine cannot allocate an object because
it is out of memory, and no more memory could be made available by the
garbage collector.
So, if a thread is not running anymore and is eligible to GC, the GC will try to collect it before throwing an OOM. Like with any other object.
is there any way to confirm if the thread is killed at the end of execution?
There's no sense confirming something you know to be true. Whenever the JVM process dies, all its threads are automatically killed by the operating system. Any other behavior is a bug in the OS.
If the garbage collector takes long time to destroy the threads even when they are available for GC, out of memory exceptions may arise.
The garbage collector doesn't kill threads - the JVM wraps operating-system-specific thread libraries into a consistent Java-language thread abstraction, so those thread libraries determine when a thread dies.
my understanding is that at the end of run method, the thread gets killed and we need not do anything explicitly to kill the thread instance.
That is correct.
If you look up in the javadoc for the Thread class you will see many methods that might help you check what you want, for example:
activeCount() : Returns the number of active threads in the current thread's thread group.
You can use this as a debug method.
isAlive() : Tests if this thread is alive.
To check if a specific thread is alive.
join() : Waits for this thread to die.
If you call this at the end of your method then it will wait for the thread to join (i.e. to end execution) before advancing. If you call for all threads, then you are sure that all have finished when the main() has finished.
destroy() : Destroys this thread, without any cleanup.
Does what it says, but I would never suggest this.
Hope it helps!

Why doesn't this thread pool get garbage collected?

In this code example, the ExecutorService is used one and allowed to go out of scope.
public static void main(String[] args)
{
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new Runnable()
{
public void run()
{
System.out.println("hello");
}
});
}
Once executorService is out of scope, it should get collected and finalized. The finalize() method in ThreadPoolExecutor calls shutdown().
/**
* Invokes {#code shutdown} when this executor is no longer
* referenced and it has no threads.
*/
protected void finalize() {
shutdown();
}
Once shutdown() is called, the pool threads should terminate and the JVM should be allowed to exit. However the executorSerivce is never getting collected and thus the JVM stays alive. Even calls to System.gc() don't seem to work. Why isn't executorService getting collected even after main() terminates?
Note: I know I should call shutdown() myself and I always do outside of testing. I'm curious why finalization isn't working as a back-up here.
This doesn't really have anything to do with GC being non-deterministic, although it doesn't help! (That is one cause in your example, but even if we 'fixed' it to eat up memory and force a collection, it still wouldn't finalize)
The Worker threads that the executor creates are inner classes that have a reference back to the executor itself. (They need it to be able to see the queue, runstate, etc!) Running threads are not garbage collected, so with each Thread in the pool having that reference, they will keep the executor alive until all threads are dead. If you don't manually do something to stop the threads, they will keep running forever and your JVM will never shut down.
Affe is correct; the thread pool's threads will keep it from being garbage collected. When you call Executors.newFixedThreadPool(3) you get a ThreadPoolExecutor constructed like so:
ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
And if you read the JavaDoc for ThreadPoolExecutor it says:
A pool that is no longer referenced in a program AND has no remaining
threads will be shutdown automatically. If you would like to ensure
that unreferenced pools are reclaimed even if users forget to call
shutdown(), then you must arrange that unused threads eventually die,
by setting appropriate keep-alive times, using a lower bound of zero
core threads and/or setting allowCoreThreadTimeOut(boolean).
If you want your thread pool to finalize like you're expecting, you should do one of those things.
If you want the threads to be finalized when the Executor service is out of scope you should avoid, as mjt suggested, the use of
ExecutorService executorService = Executors.newFixedThreadPool(3);`
and use for example:
ExecutorService executorService = new ThreadPoolExecutor(0, 3, 10, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
Because garbage collection is “non deterministic” ie you cannot predict when it will happen, you thus cannot predict exactly when the finalize method will run. You can only make Objects eligible for GC and suggest gc with System.gc() without any guarantee.
Even worse threads are OS specific handled by the JVM and are hardly predictable...
Finalizers are too unpredictable. Depending on them is usually bad practice.
You can read more about it in "Effective java" by Joshua Bloch (item 1.7)
Once executorService is out of scope, it should get collected and finalized.
Not really - once it is out of scope, it could get collected and finalized. There are no guarantees made in the VM spec about when objects are finalized, or even if they are finalized:
The Java programming language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused.

Do Java Threads need any cleanup?

I see that all the stop and destroy and anything else that deals with cleanup methods have been deprecated.
If I have a new Thread() or a class that extends Thread running, do I need to do anything in its run() method other than let it get to the end of regular execution? Or is there a background mechanism that understands that the Thread has run through all its tasks and can be destroyed?
When you call start() on your thread, native mechanism in JVM close to the operating system are starting your thread, eventually executing run(). When run() finishes, JVM takes care of everything.
You might be concerned about garbage collection or other resources cleanup. Of course if you open file/network connection inside a thread, it must be closed like everywhere else. Also the garbage collector, while analyzing live objects, takes into account objects referred from running threads. But the moment thread finishes, all the objects referenced by it (or by Runnable implementation passed to the thread) are eligible for garbage collection.
quick&dirty edit for exit method of Thread, as visible contextClassLoader is missing x.x
private void exit() {
if (group != null) {
group.remove(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
No cleanup needed. Once it finishes its task, the jvm will kill it.
The stop() method actually causes the Thread to throw an Error or Exception. The reason it is deprecated is this can happen anywhere in the code anything it modifies in a potentially unknown state. stop() is only really safe when stopping the current thread because you know when it will happen. BTW, You can catch the Error/Exception which would mean the Thread does not stop().
In any case, the result is the same, the run() returns (or fails to catch an Exception/Error). The stop() method triggers a special Error called ThreadDeath. The only thing special about it is that normally, an uncaught exception/error is printed, but this one is not. (And it doesn't have Error at the end of its name ;) You can change this behaviour if you wish.
When the Thread is no longer referenced, it can be cleaned up. (just like any other object) Note: you can hold a reference to it in another thread, preventing it from being cleaned up even thought it has finished.

Categories