6

我有一个 Java 客户端,它消耗来自服务器的大量数据。如果客户端没有以足够快的速度跟上数据流,则服务器断开套接字连接。我的客户每天断开连接几次。我运行 jconsole 来查看内存使用情况,堆空间图看起来像一个定义相当明确的锯齿模式,在大约 0.5GB 和 1.8GB 之间振荡(分配了 2GB 堆空间)。但是每次我断开连接都是在一个完整的 GC 期间(但不是在每个完整的 GC 上)。我看到完整的 GC 平均需要 1 秒多一点。根据一天中的时间,Full GC 在忙碌时每 5 分钟发生一次,或者在慢速期间 Full GC 之间最多可以间隔 30 分钟。

我怀疑如果我可以减少完整的 GC 时间,客户端将能够更好地跟上传入的数据,但我对 GC 调优没有太多经验。有没有人知道这是否是一个好主意,以及如何去做?或者是否有另一种想法也可以奏效?

** 更新 ** 我使用了 -XX:+UseConcMarkSweepGC 并且它有所改进,但在非常忙碌的时候我仍然断开连接。所以我将堆分配增加到 3GB 以帮助度过忙碌的时刻,现在它似乎运行得很好,但只有 1 天没有断开连接。也许如果我有时间,我会尝试减少产生的垃圾量,我相信这也会有所帮助。感谢所有的建议。

4

3 回答 3

14

Full GC 可能需要很长时间才能完成,而且调整起来并不容易。

一种(轻松)调整它的方法是增加堆空间——一般来说,堆空间加倍可以使两次 GC 之间的间隔加倍,但会使 GC 消耗的时间加倍。如果你运行的程序有非常清晰的使用模式,或许你可以考虑增加堆空间,让间隔变大,保证有一些空闲时间来尝试让系统执行一次GC。另一方面,按照这个逻辑,如果堆很小,那么一个完整的垃圾回收将在瞬间完成,但这似乎带来的麻烦多于帮助。

此外,-XX:+UseConcMarkSweepGC可能会有所帮助,因为它将尝试同时执行 GC 操作(不停止您的程序;请参见此处)。

这是Til Gene(Azul 系统的 CTO,高性能 JVM 的制造商,并发布了几个 GC 算法)关于 JVM 中的 GC 的一个非常好的演讲。

于 2013-05-21T18:48:29.600 回答
5

调整 Full GC 并不容易。一个更好的方法是产生更少的垃圾。产生更少的垃圾可以减少收集的压力,将对象传递到收集起来更昂贵的永久空间。

我建议您使用内存分析器

  • 减少产生的垃圾量。在许多应用中,这可以相对容易地减少 2 - 10 倍。
  • 减少您正在创建的对象的大小,例如使用原始的和较小的数据类型,如 double 而不是 BigDecimal。
  • 回收可变对象而不是丢弃它们。
  • 如果可以的话,在客户端上保留更少的数据。

通过减少您创建的垃圾量,对象更有可能在伊甸园或幸存者空间中死亡,这意味着您的完整收集要少得多,这也可以更短。

不要想当然,你必须忍受很多收藏,在极端情况下,你几乎可以完全避免它http://vanillajava.blogspot.ro/2011/06/how-to-avoid-garbage-collection.html

于 2013-05-21T19:12:50.473 回答
2

取消对 Runtime.getRuntime().gc() 的调用 - 当手动触发垃圾收集时,它要么什么都不做,要么完全停止世界垃圾收集。您希望发生增量 GC。

您是否尝试过使用 jdk 安装中的服务器 jvm?它更改了一堆默认配置设置(包括垃圾收集)并且很容易尝试 - 只需将 -server 添加到您的 java 命令中。

java -server

产生的所有垃圾是什么?你能减少它的产生吗?在可能的情况下,尝试使用 valueOf 方法。通过使用更少的内存,您可以节省 gc 和内存分配的时间。

于 2013-05-21T20:19:28.100 回答