如何增加FinalizerThread在GC中收集对象的优先级

时间:2011-11-11 11:32:45

标签: java linux jvm linux-kernel

我用profiler监视我的java应用程序以了解内存泄漏。我上课了几乎80%的记忆,这是

java.lang.ref.Finalizer

然后我谷歌上面的课程,找到了很棒的文章 http://www.fasterj.com/articles/finalizer1.shtml

现在任何人都可以建议我如何增加FinalizerThread在GC中收集这些对象的优先级。

我在Linux上使用内核版本 Linux 2.6.9-5.ELsmp(i386) Linux 2.6.18-194.17.4.el5(i386)时遇到此问题)但它在 Linux 2.6.18-128.el5PAE(i386)上工作正常(没有OOM错误)。

这个问题是因为Linux内核吗? 是否有任何JVM变量来改善FinalizerThread的优先级?

提前完成。

3 个答案:

答案 0 :(得分:2)

终结者线程应该很少做很多工作。资源应该已经发布了。确保您的代码以标准方式处理资源。

Java SE 7:

try (final Resource resource = acquire()) {
    use(resource);
}

Pre-Java SE 7:

final Resource resource = acquire();
try {
    use(resource);
} finally {
    resource.release();
}

答案 1 :(得分:2)

要按字面意思回答这个问题,你可以这样做。然而,如下所述,它可能毫无意义,特别是因为线程已经具有高优先级。

for(Thread t: Thread.getAllStackTraces().keySet())
    if (t.getName().equals("Finalizer")) {
        System.out.println(t);
        t.setPriority(Thread.MAX_PRIORITY);
        System.out.println(t);
    }

打印

Thread[Finalizer,8,system]
Thread[Finalizer,10,system]

除非您使用100%的所有核心或接近它,否则优先级无关紧要,因为即使是最低优先级也会获得所需的CPU。

注意:在Linux上,除非你是root用户,否则它会忽略提升的优先级。

相反,你应该减少终结者正在做的工作。理想情况下,它不应该有任何事情要做。终结器中高负载的一个原因是创建应该关闭但被丢弃的资源。 (留下终结者来关闭资源)

简而言之,您应该尝试确定正在最终确定哪些资源,并确保在调用finalize()时不需要执行任何操作,理想情况下根本不使用此方法。

在旧版本的Linux内核上,资源可能需要稍微长一点才能关闭。我会检查硬件是否相同,因为这可能意味着清理资源需要更长的时间。 (但真正的解决方法是确保它不需要这样做)

答案 2 :(得分:0)

正如Tom Hawtin指出的那样,您可以通过创建一个调用finalize()的{​​{1}}方法来获取FinalizerThread,然后将其隐藏在静态中。你也可以改变它的优先级。

但是很有可能它不会有任何好处。可能只有一个终结器线程。问题可能是:

  • 线程无法跟上,因为要完成的工作太多,或者
  • 线程被终结器方法中的某些东西阻挡。

(并且,我希望将已经的终结器线程标记为高优先级。)

但无论如何,我认为更好的解决方案是摆脱Thread.currentThread()方法。我打赌他们正在做一些不必要的事情......或者狡猾的事情。特别是,使用终结器从丢弃的对象中回收资源是解决该特定问题的一种不好的方法。 (见Tom Hawtin的回答。)