java gc 时间过长_如何减少长时间的GC暂停?

长时间的GC暂停对于应用程序而言是不可取的。它会影响您的SLA,导致不良的客户体验,并对关键任务应用程序造成严重损害。因此,在本文中,我列出了可能导致长时间GC暂停的主要原因,以及解决这些问题的潜在解决方案。

1.高对象创造率

如果您的应用程序的对象创建率很高,那么为了跟上它,垃圾回收率也将很高。高垃圾回收率也会增加GC暂停时间。因此,优化应用程序以创建更少的对象是减少长时间GC暂停的有效策略。这可能是一个耗时的练习,但值得100%进行。为了优化应用程序中的对象创建速率,可以考虑使用Java Profiler(如 JProfiler, YourKit或JVisualVM)。这些分析器将报告:

·

创建了哪些对象?

·

·

这些对象的创建速率是多少?

·

·

它们在内存中占用多少空间?

·

·

谁在创造它们?

·

始终尝试优化占用最大内存量的对象。追捕池塘里的大鱼。

.年龄不足的年轻一代

当年轻一代过小时,对象会过早地提升到老一代。从年轻一代收集垃圾比从年轻一代收集垃圾要花费更多的时间。因此,增加年轻代的大小有可能减少长时间的GC暂停。可以通过设置两个JVM参数之一来增加年轻一代的大小

-Xmn:指定年轻代的大小。

-XX:NewRatio:指定年轻一代相对于老一代的大小。例如,设置-XX:NewRatio = 2表示老一代与年轻一代之间的比率为1:2。年轻一代将是整个堆的一半。因此,如果堆大小为2 GB,则年轻代大小将为1 GB。

3. GC算法的选择

GC算法对GC暂停时间有很大影响。如果您是GC专家或打算成为一名GC专家(或者您团队中的某人是GC专家),则可以调整GC设置以获得最佳的GC暂停时间。如果您没有很多GC专业知识,那么我建议您使用G1 GC算法,因为它具有 自动调整 功能。在G1 GC中,您可以使用系统属性“ -XX:MaxGCPauseMillis”设置GC暂停时间目标。例:

- XX:MaxGCPauseMillis = 200

根据上面的示例,最大GC暂停时间设置为200毫秒。这是一个软目标,JVM将尽力实现这一目标。

4.交换流程

有时由于缺少内存(RAM),操作系统可能会从内存中交换应用程序。交换非常昂贵,因为它需要磁盘访问,与物理内存访问相比要慢得多。以我的拙见,在生产环境中没有认真的应用可以互换。交换过程时,GC将花费很长时间才能完成。

下面是从StackOverflow获得的脚本 (感谢作者),该脚本 在执行时将显示所有正在交换的进程。请确保您的进程没有被交换。

#!/bin/bash

# Get current swap usage for all running processes

# Erik Ljungstrom 27/05/2011

# Modified by Mikko Rantalainen 2012-08-09

# Pipe the output to "sort -nk3" to get sorted output

# Modified by Marc Methot 2014-09-18

# removed the need for sudo

SUM=0

OVERALL=0

for DIR in `find /proc/ -maxdepth 1 -type d -regex "^/proc/[0-9]+"`

do

PID=`echo $DIR | cut -d / -f 3`

PROGNAME=`ps -p $PID -o comm --no-headers`

for SWAP in `grep VmSwap $DIR/status 2>/dev/null | awk '{ print $2 }'`

do

let SUM=$SUM+$SWAP

done

if (( $SUM > 0 )); then

echo "PID=$PID swapped $SUM KB ($PROGNAME)"

fi

let OVERALL=$OVERALL+$SUM

SUM=0

done

echo "Overall swap used: $OVERALL KB"

如果发现进程正在交换,请执行以下一项操作:

为服务分配更多的RAM。

减少服务器上运行的进程数,以便它可以释放内存(RAM)。

减少应用程序的堆大小(我不建议这样做,因为它可能导致其他副作用。但是,它有可能解决您的问题)。

5.调整GC线程数

对于GC日志中报告的每个GC事件,将打印用户,sys和实时。例:

[ 时间:用户= 25.56 sys = 0.35,实际= 20.48 秒 ]

要了解这些时间之间的区别,请 阅读本文。(我强烈建议您在继续本节之前先阅读本文)。如果在GC事件中,您始终注意到“实时”时间并不比“用户”时间显着少,则可能表明GC线程不足。考虑增加GC线程数。假设“用户”时间为25秒,并且您已将GC线程数配置为5,那么实际时间应接近5秒(因为25秒/ 5个线程= 5秒)。

警告:添加过多的GC线程将消耗大量CPU,并占用应用程序资源。因此,您需要在增加GC线程数之前进行彻底的测试。

6.后台IO流量

如果文件系统的I / O活动繁重(即发生大量读写操作),这也可能导致长时间的GC暂停。这种繁重的文件系统I / O活动可能不是由您的应用程序引起的。可能是由同一台服务器上运行的另一个进程引起的。仍然可能导致您的应用程序遭受长时间的GC暂停。这是LinkedIn工程师的精彩 文章 ,详细介绍了此问题。

当繁琐的I / O活动时,您会注意到“实时”时间明显高于“用户”时间。例:

[ 时间:用户= 0.20 sys = 0.01,实际= 18.45 秒 ]

发生这种情况时,以下是一些可能的解决方案:

·

如果您的应用程序引起了很高的I / O活动,请对其进行优化。

·

·

消除导致服务器上大量I / O活动的进程。

·

·

将您的应用程序移到I / O活动较少的其他服务器上。

·

提示:如何监视I / O活动

您可以在Unix中使用sar (系统活动报告) 监视I / O活动 。例:

sar -d -p 1

上面的命令每1秒报告一次对设备的读取/秒和写入/秒。有关“ sar”命令的更多详细信息,请参考 本教程。

7. System.gc()调用

当 System.gc()的 或 调用Runtime.getRuntime()。GC() 方法调用被调用时,它会导致停止的世界充满选区。在世界各地的完整GC期间,整个JVM被冻结(即,在此期间将不执行任何用户活动)。从以下来源之一进行System.gc()调用:

1. 您自己的开发人员可能会显式调用System.gc()方法。

2. 它可能是第三方库,框架,有时甚至是您使用的应用程序服务器。任何这些都可能调用System.gc()方法。

3. 可以通过使用JMX从外部工具(如VisualVM)触发。

4. 如果您的应用程序正在使用RMI,则RMI会定期调用System.gc()。可以使用以下系统属性来配置此间隔:

-Dsun.rmi.dgc.server.gcInterval=n

-Dsun.rmi.dgc.client.gcInterval=n

评估是否绝对需要显式调用System.gc()。如果不需要,请删除它。另一方面,可以通过传递JVM参数来强制禁用System.gc()调用:-XX:+ DisableExplicitGC。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值