现象

从监控来看,堆内存是够用的,但是频繁触发Full GC,每秒钟三次,每次耗时三四秒。

image.png

结合Young GC的信息和堆内存的使用情况,可以发现新生代的内存够用,老生代的内存不够用,频繁Full GC,老生代的内存使用率依旧达到了98%。

2018-11-20T15:02:46.002+0800: 2779214.232: [GC2018-11-20T15:02:46.002+0800: 2779214.232: [ParNew: 1643604K->4513K(1843200K), 0.0129920 secs] 4994360K->3355569K(5257216K), 0.0131040 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]

$ sudo jmap -heap 11927

Attaching to process ID 11927, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 24.65-b04-internal

using parallel threads in the new generation.

using thread-local object allocation.

Concurrent Mark-Sweep GC

Heap Configuration:

MinHeapFreeRatio = 40

MaxHeapFreeRatio = 70

MaxHeapSize = 5593104384 (5334.0MB)

NewSize = 2097152000 (2000.0MB)

MaxNewSize = 2097152000 (2000.0MB)

OldSize = 5439488 (5.1875MB)

NewRatio = 2

SurvivorRatio = 8

PermSize = 536870912 (512.0MB)

MaxPermSize = 536870912 (512.0MB)

G1HeapRegionSize = 0 (0.0MB)

Heap Usage:

New Generation (Eden + 1 Survivor Space):

capacity = 1887436800 (1800.0MB)

used = 899619040 (857.9435729980469MB)

free = 987817760 (942.0564270019531MB)

47.66353183322482% used

Eden Space:

capacity = 1677721600 (1600.0MB)

used = 895864384 (854.3628540039062MB)

free = 781857216 (745.6371459960938MB)

53.39767837524414% used

From Space:

capacity = 209715200 (200.0MB)

used = 3754656 (3.580718994140625MB)

free = 205960544 (196.41928100585938MB)

1.7903594970703125% used

To Space:

capacity = 209715200 (200.0MB)

used = 0 (0.0MB)

free = 209715200 (200.0MB)

0.0% used

concurrent mark-sweep generation:

capacity = 3495952384 (3334.0MB)

used = 3432530640 (3273.516311645508MB)

free = 63421744 (60.48368835449219MB)

98.18585217892945% used

Perm Generation:

capacity = 536870912 (512.0MB)

used = 52807616 (50.36126708984375MB)

free = 484063296 (461.63873291015625MB)

9.836184978485107% used

28784 interned Strings occupying 3175392 bytes.

排查过程

这种现象表明,服务存在内存泄露,所以需要分析堆的使用。使用gcore产生core文件,这比直接使用jmap dump快得多,可以避免对线上服务造成影响。core文件的大小跟进程使用的堆大小一样大。

$ sudo gcore 11927

[Thread debugging using libthread_db enabled]

[New Thread 0x487ac940 (LWP 1653)]

[New Thread 0x486ab940 (LWP 1652)]

[New Thread 0x485aa940 (LWP 1651)]

0x00000030f0e07ba5 in pthread_join () from /lib64/libpthread.so.0

Saved corefile core.11927

使用jmap将core文件转换成bin文件。hprof文件跟进程实际使用的堆内存一样大。

$sudo jmap -dump:format=b,file=heap.hprof.bin /opt/taobao/java/bin/java core.11927

Attaching to core core.11927 from executable /opt/taobao/java/bin/java, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 24.65-b04-internal

Dumping heap to heap.hprof.bin ...

这个转换过程非常慢。将5.3GB的core转换成4GB的hprof文件,花了将近半个小时。通过top来看,这个dump是单线程做的,一直跑满了一个核。

top - 15:43:38 up 214 days, 1:02, 2 users, load average: 1.69, 1.83, 1.56

Tasks: 142 total, 1 running, 141 sleeping, 0 stopped, 0 zombie

Cpu(s): 51.5%us, 0.8%sy, 0.0%ni, 47.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

Mem: 8194164k total, 8135628k used, 58536k free, 75324k buffers

Swap: 0k total, 0k used, 0k free, 797688k cached

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

11927 www 20 0 6513m 5.3g 82m S 105.5 67.4 10760:36 java

3764 root 20 0 2458m 791m 12m S 100.5 9.9 18:53.36 jmap

16376 root 20 0 411m 360m 1468 S 0.0 4.5 19:52.15 syslog-ng

11190 agent 20 0 540m 143m 5832 S 0.0 1.8 65:14.77 java

接着就是如何分析这个hprof文件的问题。目前主流的分析工具,有MAT和jhat,下面分别使用二者分析一下。

jhat

jhat看起来比较简单,从分析结果里面可以看出用户自定义类中,SlsRecordWriter类的对象比较多,再做进一步的分析就不知如何下手了。

image.png

image.png

MAT

MAT体验比较好,直接分析出持有内存最大的类,然后从dominator_tree里面可以看到具体的应用情况,可以发现SlsRecordWriter对象很多。需要注意的是,使用MAT分析大的dump文件很吃内存,所以需要调大堆内存。Mac上Eclipse的配置文件路径是/Applications/Eclipse.app/Contents/Eclipse/eclipse.ini。

image.png

image.png

结论

构造一个demo验证一下。下面这个例子,运行一段时间便会触发Young GC(IDEA VM options设置上"-verbose:gc -XX:+PrintGCDetails"),但是从来不会调用Foo的finalize方法,只有停止运行的时候,才会进入hook执行,接着释放对象。如果注释掉addShutdownHook这段代码,就符合期望了。所以addShutdownHook会导致Runtime持有对象,需要注意使用场景。

class Foo {

private String bar = new String("fdsaflkjdsalfjldsajflsajfoiwefnaslfjlaskejfowieajfalfjelajfieslkjflksdajlf");

private int num = 0;

public Foo() {

}

public Foo(int num) {

System.out.println(String.format("Foo initialize: %d", num));

this.num = num;

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

public void run() {

clean();

}

}));

}

void clean() {

System.out.println(String.format("Foo clean: %d", num));

}

@Override

protected void finalize() throws Throwable {

super.finalize();

System.out.println(String.format("foo finalize: %d", this.num));

}

}

public class Demo {

public static void main(String[] args) {

int num = 0;

while (true) {

try {

Foo foo = new Foo(num);

num += 1;

Thread.sleep(100);

}catch (Exception e) {

}

}

}

}

参考资料

java gc full gc_记一次Java服务频繁Full GC的排查过程相关推荐

  1. 记一次.Net Core程序启动失败的排查过程

    阅文时长 | 2分钟 字数统计 | 3212字符 主要内容 | 1.引言&背景 2.排查.NetCore启动失败详细过程 3.声明与参考资料 『记一次.Net Core程序启动失败的排查过程』 ...

  2. 网页java挂挖矿_记一次服务器被植入挖矿脚本的解决过程

    记一次服务器被植入挖矿脚本的解决过程 删除挖矿脚本和对应的进程 找出并删除对应挖矿脚本文件 找出进程pid,并且kill掉 无法kill掉的是原进程的守护进程,原进程不在它也会自动关闭,所以不用管它 ...

  3. 记一次线上cpu飙升100%的排查过程

    大家好,我是烤鸭: 最近没怎么写技术文章,还是得回归下初心,正好前几天出现个线上问题,记录下排查过程. 问题描述 某个时间点,接收到接口响应慢报警. 过一会收到服务器cpu可用率低(<10%)报 ...

  4. java电话面试_记一次java电话面试

    答案补充中... 一.java基础 1.简述java的几种基本数据类型 JAVA的基本数据类型有:byte.char.boolean.short.int.long.float.double 2.什么是 ...

  5. java三元运算_记一次java中三元表达式的坑(避免踩坑)

    近期一直在刷算法,原创文章写的也比较少,今天的主题不算是一个很大的问题,是我做题的时候出来的,而且还曾在A厂的公众号上看到过,今天自己整理一下,避免大家入坑. 这个问题是三元表达式会在计算的时候出现拆 ...

  6. 记一次 Kubernetes 集群 Pod Eviction 问题排查过程

    声明: 本博客欢迎转发,但请保留原作者信息! 新浪微博:@Lingxian_kong; 微信公众号:飞翔的尘埃; 内容系本人学习.研究和总结,如有雷同,实属荣幸! 现象:一个普通的 k8s 集群,3 ...

  7. java什么时会出现gc_面试题:java GC发生在会么时候,对什么东西,做了什么事情...

    转自cy609329119的 面试题:"你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?" 面试题目: 地球人都知道,Java有个东西叫垃圾收集器,它让创建的对 ...

  8. java排查full gc_一次频繁Full GC问题排查过程分享

    问题描述 应用收到频繁Full GC告警 问题排查 登录到对应机器上去,查看GC日志,发现YGC一分钟已经达到了15次,比Full GC还要频繁一些,其中Full GC平均10分钟超过了4次,如下图 ...

  9. java年轻代频繁gc_年轻代频繁ParNew GC,导致http服务rt飙高

    背景介绍 某日下午大约四点多,接到合作方消息,线上环境,我这边维护的某http服务突然大量超时(对方超时时间设置为300ms),我迅速到鹰眼平台开启采样,发现该服务平均QPS到了120左右,平均RT在 ...

最新文章

  1. 从易到难,针对复杂问题的无监督式问题分解方法
  2. 二叉树的广度优先遍历(层序遍历)
  3. php flash chat,FlashChat lt;= 4.5.7 (aedating4CMS.php) Remote File Include Vulnerability
  4. 企业级私有registry Harbor通过https访问的详细配置
  5. 苹果Mac 软件出现「意外退出」及「打不开」解决方法
  6. colorpix取色器
  7. 在SQL Server中导入数据库(.mdf格式)
  8. Pomodoro Technique番茄钟的理解
  9. android基础的博客,【复习】Android基础
  10. Visual Studio 2012 编译C
  11. 保罗·奥兰德:预测金融市场走势
  12. PVE 定时关机 定时开机
  13. Origin与OriginPro 版本一览图
  14. Oracle数据库实例之内存架构(一)
  15. laravel银联支付
  16. nginx: [emerg] unknown directive ssl  Nginx配置SSL报错
  17. 【无标题】拼多多商品详情API接口
  18. 学历造假!AI公司CEO冒充中科大少年班校友!清华、斯坦福名校经历全造假
  19. 【模板题】欧拉函数与线性筛求欧拉函数
  20. undefined reference to winmain

热门文章

  1. 一文览尽ToF深度相机技术
  2. OpenCV中initUndistortRectifyMap函数存在bug原因探究
  3. CentOS 7(64位)系统中安装AutoDockTools(MGLTools)
  4. 其他算法-高斯白噪声
  5. mysql根据当前时间删除_从日期时间早于另一项日期时间的Mysql表中删除
  6. 物理机linux无法上网,物理机不能访问虚拟机VMNet8中的Linux
  7. 华为充电器接口叫什么_插座USB接口跟手机充电器有什么不同_电工百科
  8. 75分钟入门微生物组数据分析和结果解读—刘永鑫(合肥,2021年6月23日)
  9. Gut Microbes:中科院微生物所王军组在新冠病人肠道病毒组研究取得新进展
  10. 微生物预测年龄,皮肤比肠道更准确