您的位置 首页 java

线上问题解决:java之full gc问题分析,定位及解决

  • ① 启动参数配置

-Xms2g -Xmx2g JVM 堆内存 的最小值,最大值设置成相等的。

预热过程(堆内存小于最小值),慢慢的增长到最小值,而不是直接打到最小值的2g,如果需要直接像操作系统申请足够的内存,请在参数中增加:-XX:+AlwaysPreTouch,直接申请2g的内存。

  • ② GC

了解GC的配置,而不是需要了解GC代码是怎么写,其实就是熟悉 JVM 的应用,还有JVM的更新信息,一定要跟着官网走肯定是没有错的。要掌握的是梳理的方式。很多事情不是出了问题去解决,很多时候是提前的预防工作。

线上的系统:GC的并行 (-XX:+UseParNewGC) + CMS机制(用户线程和GC线程同步),官方建议是G1,不久将来肯定都是G1。

提前的预防:日志不能缺少。不要stop the world,运行过程中犹豫GC导致的停顿,暂停,java代码运行不了,需要一定的时间进行垃圾回收。

打印gc的信息,filepath是日志的路径。

-verbose:gc -XX:+PrintGCDetails -Xloggc:filepath -XX:+HeapDumpOnOutOfMemoryError
 
  • ② 代码写作错误

正常的情况下,不需要控制gc,依赖操作系统的gc就够了,但是代码里面却写了 system .gc()。导致程序不稳定。写这个比较头疼,不像写其他的异常,在高并发场景或者特殊场景下面,应用暂停,应用无法访问,如何排查,首先需要了解,那些情况会出现full gc的情况,内存不够用固然是一个方面,很多时候代码写的有问题。

下面这段代码,本身设置512m的内存,结果每次申请256M的内存,明显内存不够,进行了gc。还有个gc就是代码里面自带的gc情况。

// 频繁调用system.gc导致fullgc次数过多
// 使用 server 模式运行 开启GC日志
// -Xmx512m -server -verbose:gc -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
public class FullGCDemo1 {
 public static void main(String[] args) throws InterruptedException {

 for (int i = 0; i < 1000; i++) {
 byte[] tmp = new byte[1024 * 1024 * 256]; // 256兆
 System.gc(); // 8G堆 128兆。full GC
 System.out.println("我GC一次了");
 Thread.sleep(2000L);
 }
 }
}
 

  • ③ 案例分析

一个服务器部署了一个应用,这个应用有很多的功能,其中有个execl的表格读取。用到了一个jar,JXL。

pom .xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http:// maven . apache .org/POM/4.0.0"
 xmlns:xsi="#34;
 xsi:schemaLocation=" #34;>
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.study.jvm</groupId>
 <artifactId>om-demo</artifactId>
 <version>1.0.0</version>
 < build >
 < plugin s>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 < configuration >
 <source>8</source>
 <target>8</target>
 </configuration>
 </plugin>
 </plugins>
 </build>
 <dependencies>
 <dependency>
 <groupId>net.sourceforge.jexcelapi</groupId>
 <artifactId>jxl</artifactId>
 <version>2.6.12</version>
 </dependency>
 <!-- 自动下不了,就手动添加到自己的maven本地仓库 -->
 <!--  -->
 <dependency>
 <groupId>com.dianping.cat</groupId>
 <artifactId>cat-client</artifactId>
 <version>3.0.0</version>
 </dependency>

 </dependencies>

</project>
 
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.WorkbookSettings;

import java.io.File;

// 使用server模式运行 开启GC日志
// -Xmx512m -server -verbose:gc -XX:+PrintGCDetails
// 很多人都会建议的规避System.gc带来的fullgc风险 -XX:+DisableExplicitGC 禁止程序显示调用gc方法
public class FullGCDemo2 {
 public static void main(String[] args) throws Exception {
 for (int i = 0; i < 1000; i++) {

 Workbook book = Workbook.getWorkbook(new File(FullGCDemo2.class.getClassLoader().getResource("FullGCDemo2.xls").getFile()));
 // 获得第一个工作表对象
 Sheet sheet = book.getSheet(0);
 // 得到第一列第一行的单元格
 Cell cell1 = sheet.getCell(0, 0);
 String result = cell1.getContents();
 System.out.println(result);
 book.close(); // 第三方依赖包,内部可能适用了system.gc()
 Thread.sleep(2000L);
 }
 }
}

 

resources 目录下 添加一个excel文件

excel文件

正常情况下没有任何的报错

加入gc的监控看看,发现了很多System.gc();

检查发现源码中存在Sytem.gc() ,本以为开源代码很健全谁料,这么多坑,真是防不胜防啊,怎么办?

其实别人在写开源的代码都想到了。仔细看里面的源码发现。

再次运行,发现没有full gc的情况了。

总结下,可能这一个框架有可以禁用gc,一个大项目用了很多框架我不可能每个都看看源码吧,所以需要提前做性能的测试,发现里面的System.gc();解决他。但是有可能有的框架本身必须需要进行gc,例如大数据这块。其实这就是调优去衡量,那些需要gc,那些不需要gc。太极玩的就是一个平衡,并不是这个事情多严重,但是这个坑一定得注意,这就是性能测试的必要性。小功能的jar自带的gc,可能导致这个系统的gc,本来10秒一次的gc,因为这个小功能1秒中gc一次,导致整个系统也是1秒1个次,本身开发系统就是为了减少耦合。针对这些问题应该如何解决。 dubbo 这个框架里面引用了spring框架,其实根本没有引用里面的jar,而是把里面的源码放到dubbo的一个包下面,做定制的开发,这样我可以控制gc了。这就可以完全避免耦合性,因为代码都是我的,我可以随意的控制。一定要检查第三方包的使用情况。

在jdk很多源码中都存在 //help GC,其实就是first =null 这样就释放了,gc就自动的回收了。针对文件导入excel中需要通过list导入,list里面有10万条数据,导入后,可能list就不管了,如果想让jvm跑的更快的话,可以在最后写个list= null。jvm在做垃圾回收计算的时候,就不需要做任何分析直接就回收掉了。

PC: 通过上边的代码应该可以明白,jvm在做回收统计的时候真得会一个一个统计的。开发时,借鉴线程安全,接触到大数据的地方,就有泄露的可能,被反被执行,也有可能出现泄露。

文章来源:智云一二三科技

文章标题:线上问题解决:java之full gc问题分析,定位及解决

文章地址:https://www.zhihuclub.com/175668.shtml

关于作者: 智云科技

热门文章

网站地图