scala - Scala actor应用程序的奇怪GC行为

标签 scala garbage-collection jvm actor out-of-memory

我有an application which uses rather a lot of actors:准确地说是25,000。它使用Scala 2.7.7并在 jdk6_u18 上运行。它基本上监听和处理市场数据,并且状态很少。

它每天早上8.02开始,并在一个小时内以OutOfMemoryError崩溃。您说“啊哈”,“您的内存泄漏了!”除非我重新启动它,否则永远不会崩溃在一天的剩余时间内再次崩溃!尽管在美国市场下午2:30开盘时,GC和CPU的开销都增加了,但这仍然没有问题。

一些轶事发现:

  • 它在Solaris上运行。当我以前在Linux上运行它时,它从未崩溃过。
  • 我尝试弄乱世代堆大小,分配更多内存等。我认为
  • 没什么区别
  • 当我打开
  • verbose:gc时,收集器的行为似乎有所不同

    出现一些问题:
  • 为什么该程序的行为在Linux和Solaris之间会有所不同?
  • 从8.02开始到8.42之间,为什么行为会有所不同?
  • 我听说actors库存在一些内存泄漏问题。他们是什么人,什么时候被固定的,我怎么会发现这里是否发生了类似的事情? (在jhat等中查找的内容)
  • 是否有人对发生的事情有所了解?

  • 我现在正在尝试G1看看是否有任何区别。我明天将更新这个问题!

    G1的一些输出,带有verbose:gc

    我想我只是在演戏中发现了它:

    600.290: [Full GC 255M->144M(256M), 1.5772616 secs]
    602.084: [GC pause (young) 227M->145M(256M), 0.0556769 secs]
    602.418: [Full GC 254M->144M(256M), 1.6415216 secs]
    604.279: [GC pause (young) 227M->145M(256M), 0.0415157 secs]
    604.602: [Full GC 255M->145M(256M), 1.6041762 secs]
    606.422: [GC pause (young) 227M->145M(256M), 0.0237441 secs]
    606.710: [Full GC 254M->145M(256M), 1.6022185 secs]



    然后再过一会儿(您可以看到完整的GC花了更长的时间,而回收的时间却更少了)

    849.084: [Full GC 254M->176M(256M), 1.9658754 secs]
    851.191: [GC pause (young) 228M->176M(256M), 0.0218611 secs]
    851.414: [Full GC 254M->176M(256M), 1.9352357 secs]
    853.492: [GC pause (young) 228M->176M(256M), 0.0224688 secs]
    853.716: [Full GC 254M->176M(256M), 1.9339705 secs]
    855.793: [GC pause (young) 228M->176M(256M), 0.0215707 secs]
    856.009: [Full GC 254M->176M(256M), 1.9805797 secs]
    858.137: [GC pause (young) 228M->176M(256M), 0.0223224 secs]



    G1的一些输出,带有verbose:gc off

    很好! *叹*

    303.656: [GC pause (young) 225M->93M(256M), 0.1680767 secs]
    308.060: [GC pause (young) 226M->94M(256M), 0.1793724 secs]
    312.746: [GC pause (young) 227M->93M(256M), 0.1674851 secs]
    316.162: [GC pause (young) 227M->95M(256M), 0.1826145 secs]
    320.147: [GC pause (young) 226M->94M(256M), 0.1656664 secs]
    325.978: [GC pause (young) 226M->93M(256M), 0.1475760 secs]
    330.176: [GC pause (young) 226M->94M(256M), 0.1727795 secs]



    而且很多以后它仍然可以!

    25882.894: [GC pause (young) 224M->125M(256M), 0.2126515 secs]
    25884.880: [GC pause (young) 224M->126M(256M), 0.2059802 secs]
    25887.027: [GC pause (young) 224M->125M(256M), 0.1851359 secs]
    25889.940: [GC pause (young) 223M->126M(256M), 0.2046496 secs]
    25891.567: [GC pause (young) 224M->126M(256M), 0.1600574 secs]



    再后来,一个完整的GC

    37180.191: [GC pause (young) 225M->154M(256M), 0.1716404 secs]
    37182.163: [GC pause (young) (initial-mark) 225M->153M(256M)37182.326: [GC concurrent-mark-start], 0.1622246 secs]
    37183.089: [GC concurrent-mark-end, 0.7635219 sec]
    37183.090: [GC remark, 0.0032547 secs]
    37183.093: [GC concurrent-count-start]
    37183.297: [GC concurrent-count-end, 0.2043307]
    37183.393: [GC cleanup 198M->198M(256M), 0.0068127 secs]
    37183.400: [GC concurrent-cleanup-start]
    37183.400: [GC concurrent-cleanup-end, 0.0000393]
    37183.648: [GC pause (young) 222M->153M(256M), 0.1483041 secs]
    37184.235: [GC pause (partial) 171M->91M(256M), 0.2520714 secs]
    37187.223: [GC pause (young) 221M->92M(256M), 0.1721220 secs]



    更新

    好吧,自从在jdk1.6.0_18上切换到G1垃圾收集器以来,该应用程序已经连续三天表现良好。我怀疑埃里克(Erik)对虚拟机在高吞吐量情况下陷入死亡螺旋的情况的分析是正确的,在这种情况下,虚拟机已将对象提升为终身制。

    最佳答案

    您是否有任何理由期望堆的大小逐渐增加?看起来在两条痕迹中它都在增长。我在许多情况下所做的一件事是减少堆,以使问题变得更糟。但是,256M大约是Scala的下限。

    我以前注意到的一件事是,如果由于压力太大而使生命周期短的物体从伊甸园世代中脱颖而出,它可能会逐渐使您丧命。当事件量很大(也许您早上有时间吗?)并且您的伊甸园空间不够大时,可能会发生这种情况。总体来说,斯卡拉(Scala)尤其是 Actor 大量使用了小巧的小 object ,而且似乎有一个神奇的阈值,一旦您越过它,它就会全部下坡。因此,一次运行就可以了,下一次崩溃并烧毁。

    我之前注意到的另一件事是,在OSX/x86上运行良好的GC设置在Sparc/Solaris上通常无法正常运行,反之亦然。如果您使用的是CoolThreads,建议您将GC配置为在调度程序/池中每个线程有一个GC线程。

    这带来了另一件事-确保调度程序不会随意创建新线程。有时会那样做。我要说的是,几乎应该总是手动设置线程的上限。我不知道它的相关性如何,但是actor默认使用的关于fork-join调度程序的一个有趣的事实是,它旨在用于短期的,CPU限制的任务。在它管理的线程中执行IO会加重其假设。当然它应该仍然可以工作,但是...

    祝你好运!我已经因为这类问题而失去了很多很多天。

    看一下这里的一些选项:http://java.sun.com/performance/reference/whitepapers/tuning.html

    看起来您正在使用并发标记清除收集器。尝试设置:

    -XX:+UseParallelGC
    

    关于scala - Scala actor应用程序的奇怪GC行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2183226/

    相关文章:

    scala - 使用 Spark SQL GROUP BY 对 DataFrame 进行高效的 PairRDD 操作

    c# - 返回值内存范围

    java - 优化 Xms/Xmx/XX :MaxPermSize in JVM

    java - 调度线程时的 JVM 公平性

    scala - 使用 spark-scala 删除数据框的最后一列

    scala - 从 Shapeless-guide 通用派生 Typeclass

    c++ - node.js native 插件 - 包装类的析构函数不运行

    java - 如何从字符串从 Kotlin 类转换为接口(interface)/类?

    clojure - 为什么在 clojure 中实现协议(protocol)时出现 "Unsupported binding form"错误?

    scala - 加上不能在 Scala 解释器中工作