Java 如何找到耗时的终结器

Java 如何找到耗时的终结器,java,garbage-collection,jvm,finalizer,finalize,Java,Garbage Collection,Jvm,Finalizer,Finalize,我正在开发一个应用程序,其目的是尽可能快地计算报表 我的应用程序使用了大量内存;100多人去了 自上次发布以来,我注意到性能大幅下降。我的调查显示,在计算过程中,我在40到60秒之间进行了多次垃圾收集!!! (JMC告诉我它们是SerialOld,但我不知道它的确切含义)当然,当JVM进行垃圾收集时,应用程序被完全冻结 我现在正在调查这些垃圾收集的来源。。。这是一项非常艰苦的工作 我怀疑,如果这些垃圾收集这么长,那是因为它们在finalize函数中花费了很多时间(我知道,在我们从其他团队集成的所

我正在开发一个应用程序,其目的是尽可能快地计算报表

我的应用程序使用了大量内存;100多人去了

自上次发布以来,我注意到性能大幅下降。我的调查显示,在计算过程中,我在40到60秒之间进行了多次垃圾收集!!! (JMC告诉我它们是SerialOld,但我不知道它的确切含义)当然,当JVM进行垃圾收集时,应用程序被完全冻结

我现在正在调查这些垃圾收集的来源。。。这是一项非常艰苦的工作

我怀疑,如果这些垃圾收集这么长,那是因为它们在
finalize
函数中花费了很多时间(我知道,在我们从其他团队集成的所有库中,有些库使用finalizer)

然而,我不知道如何证实(或不证实)这个假设;如何找到耗时的终结器

我正在寻找一个好的工具,甚至是一个好的方法

以下是通过JVisualVM收集的数据

正如您所看到的,当我有一个 原木垃圾

令人惊讶的是,当我使用JVisualVM时,上面的图表 有规律地从右向左滚动。当旧垃圾被丢弃时 触发后,滚动停止(直到这里,它看起来正常,这是 世界末日)。但是,当滚动突然重新启动时,它确实启动了 不是从旧垃圾的结尾,而是从挂起的序列化程序的结尾

这让我觉得终结器阻塞了JVM

有人对此有解释吗

多谢各位
Philippe

以下是我将要做的,以调查您的终结器理论

  • 使用您喜爱的Java探查器启动JVM

  • 让它运行足够长的时间,以获得一个完整的堆

  • 启动探查器

  • 触发垃圾回收

  • 停止探查器


  • 现在,您可以使用探查器信息来确定哪些(如果有)
    finalize
    方法使用了大量时间


    然而,我怀疑真正的问题将是内存泄漏,并且您的JVM已经到了堆被无法恢复的对象填满的地步。这可以解释频繁的“SerialOld”垃圾收集

    或者,这可能只是一个大的堆问题。100Gb是。。。大

    我的应用程序使用了大量内存;100多人去了

    JMC告诉我它们很老了,但我不知道它的确切含义


    如果将串行收集器用于100GB堆,则可能会出现长时间的暂停,因为串行收集器是单线程的,并且一个内核每单位时间只能占用这么多内存

    只需选择任意一个多线程收集器就可以减少暂停时间

    然而,我不知道如何证实(或不证实)这个假设;如何找到耗时的终结器


    一般来说:收集更多的数据。对于与GC相关的事情,您需要启用GC日志,对于在java代码(无论是您的应用程序还是第三方库)中花费的时间,您需要一个探查器。

    finalize
    方法在垃圾收集期间不会执行。确定吗?即使是“旧”垃圾收集?谢谢你的回答。在非并发GC阶段没有运行Java代码。GC只发现可终结对象并将其添加到队列中。该队列稍后由Java线程处理,Java线程与其他Java线程一起运行。好,清除。再次感谢。“此队列稍后由终结器Java线程处理”这是否意味着它们是按顺序运行的?JVM有多少个“终结器Java线程”?就一个?终结器线程的数量是否可以通过JVM参数自定义?(这些问题是针对我自己的文化,但我不认为它们与我的原始版本有关)是的,只有一个终结器线程按顺序运行所有终结器。仅供参考,我使用的是G1GC垃圾收集器“如果您使用的是串行收集器”1)串行收集器是什么意思?2) 你是说我可以用另一个吗?怎么做?你的问题是SerialOld,这与G1GC是相互排斥的。怎么用?关于堆栈溢出,还有许多其他的答案,oracle的垃圾收集器文档也是如此。SerialOld!=G1GC,您不能同时使用两者。但是,当查看有问题的garbadge集合(持续时间约为40-60秒)时,JMC将它们标记为“SerialOld”。当然,我使用的是G1GC