java-如何停止许多并发线程的句柄泄漏

时间:2019-03-14 03:37:39

标签: java multithreading

我遇到了明显的句柄泄漏,但是我希望有一种解决方法,或者我只是误解了JRE如何在内部处理线程。

请注意,此问题的答案不是“使用线程池并限制并发线程的最大数量”。这不能解决潜在的问题或可能的解决方案,特别是在需要大量最大同时线程的情况下。

如果我一次创建并启动许多线程,则会分配很多句柄。这是很合理的。但是,当这些线程全部结束时,大多数分配的句柄不会释放。

Process Explorer的句柄计数如下:

峰值-创建并运行600个线程后的最大句柄数

线程已结束-在所有600个线程都结束(仅离开主线程和JVM线程)之后处理计数

           Handle Counts
JRE    Peak    Threads Ended
1.4    2632    232
5      3859    259
6      4311    3111
8      4321    3121

这里有两个主要观察结果:

  1. JRE 5和更高版本的线程处理开销明显高于1.4
  2. JRE 6和更高版本在线程结束后没有释放句柄

重复创建和启动相同或更少数量的线程并不会增加Peak / Ended句柄计数(除非使用JRE 1.5,否则泄漏速度可能会更慢)。增加最大同时线程数会同时增加两个数字。

所有用于测试的JRE都是Sun / Oracle的。

GC从来没有出现过,并且根据几天的测试和观察问题来清理混乱。

有人知道如何确保在Java 6和更高版本中使用线程之后释放线程的句柄资源,而无需重新启动JVM吗?

重现该问题的测试代码如下:

public class ThreadLeakTest 
{
    public static void main(String[] args) 
    {
        new ThreadLeakTest();
    }

    public ThreadLeakTest()
    {
        while (true)
        {
            for (int i = 0; i < 600; ++i)
            {
                LeakTestThread testThread = new LeakTestThread();
                Thread t = new Thread(testThread);
                t.start();
            }

            sleepSafe(20000);
        }
    }

    private class LeakTestThread implements Runnable
    {
        public void run()
        {
            sleepSafe(15000);
        }
    }

    private static final void sleepSafe(int sleepTime)
    {
        try
        {   
            Thread.sleep(sleepTime);
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

似乎是一个已知的错误,8154063

  

VM维护一个PlatformEvent对象池(映射到Windows上的Events)。此池将一次达到VM中存在的并发线程的最大数量所需的最大值。我们倾向于先用完内存以在不使用Handles之前创建线程。因此,在第一次睡眠期间,仅存在主线程和几个VM线程,并且总句柄数量很少。

     

然后,我们启动3000个线程,每个线程至少使用5个Handle(并且根据报告的输出,我假设某处实现中有第6个隐藏项)。然后,根据计算机的大小和调度情况,并发线程数会有所不同,但是假设所有线程数均为3000,那么很容易看出峰值的来源。

因此,对于Windows,除了减少线程数量之外,似乎没有很好的解决方案。除此之外,还有一个更笼统的想法:似乎您将硬件用于“实际”服务器任务。如果是这样,请考虑:

  • 使用比Java更好的操作系统(这是为什么如今有这么多大型服务器运行Linux的原因)
  • 如果必须使用Windows,则可以考虑使用与它“更近”的平台,例如.NET和C#。或者,您决定使用像Akka这样的JVM框架,该框架无需大量线程即可实现其“并行”。