How to reclaim the memory used by a Java thread st

2019-05-25 19:21发布

问题:

I've been having this memory leak issue for days and I think I have some clues now. The memory of my java process keeps growing but yet the heap does not increase. I was told that this is possible if I create many threads, because Java threads uses memory outside of the heap.

My java process is a server type program so there are 1000-2000 threads. Created and deleted ongoing. How do I reclaim the memory used by a java thread? Do I simply erase all references to the thread object and make sure that this is terminated?

回答1:

Yes. That is the answer. As long as there is an active reference to any Java object, then that object won't be garbage collected when it's done. If you're creating and destroying threads and not pooling them, I think you have other issues as well.



回答2:

From the Java API docs threads die when:

All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

Threads die when they return from their run() method. When they die they are candidates for garbage collection. You should make sure that your threads release all references to objects and exit the run() method.

I don't think that nulling references to your threads will really do the trick.

You should also check out the new threading facilities in Java 5 and up. Check the package java.util.concurrent in the API documentation here.

I also recommend you to check the book Concurrency in Practice. It's being priceless for me.



回答3:

There are two things that will cause a Thread to be not garbage collected.

  1. Any thread that is still alive will not be garbage collected. A thread is alive until the run method called by Thread.start() exits, either normally or by throwing an exception. Once this happens (and the thread's uncaught exception handler has finished), the thread is dead.

  2. Any live reference to the Thread object for a thread will prevent it from being garbage collected. The live reference could be in your code, or if you are using thread pools, they could be part of the pool data structures.


The memory of my java process keeps growing but yet the heap does not increase.

That would be because each thread has a large (e.g. 1Mb) stack segment that is not allocated in the Java heap.

A thread's stack segment is only allocated when the thread is started, and released as soon as the thread terminates. The same also applies (I think) to the thread's thread-local map. A Thread object that is not "alive" doesn't use much memory at all.


So to sum it up. You appear to have lots of live threads. They won't be garbage collected as long as they are alive, and the only way to make them release their memory is to cause them to die ... somehow.

To reduce memory usage, you to need to do one or more of:

  • Look at the thread code (the run() methods, etc) to figure out why they are still hanging around.
  • Reduce the size of the thread stacks. (In theory, you can go as low as 64K ...)
  • Redesign your app so that it doesn't create thousands of threads. (Thread pools and some kind of work queue is one possible approach.)


回答4:

That is a lot of threads, each of which imposes a memory overhead, and well as other resources for managing them (context switching etc). Use a profiler to view the thread activity - you'll likely find that most of the threads are idle most of the time.

I'd suggest the first step is to look at managing the threads using the thread pools provided by java.util.concurrent. Rather than creating threads, look to create tasks that are handed off to the pools. Tweak the pools until you have a much smaller number of threads that are kept reasonably busy. This may well resolve the memory issue; it will certainly improve performance.