结合生产环境的一些案例,可能有些案例,你知道了,或者是听说过,可能你还不了解,一起说下,过下生产中的问题。
full gc
- ① 启动参数配置
-Xms2g -Xmx2g JVM堆内存的最小值,最大值设置成相等的。
预热过程(堆内存小于最小值),慢慢的增长到最小值,而不是直接打到最小值的2g,如果需要直接像操作系统申请足够的内存,请在参数中增加:-XX: AlwaysPreTouch,直接申请2g的内存。
- ② GC
代码语言:javascript复制了解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
- ② 代码写作错误
代码语言:javascript复制正常的情况下,不需要控制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);
}
}
}
- ③ 案例分析
代码语言:javascript复制一个服务器部署了一个应用,这个应用有很多的功能,其中有个execl的表格读取。用到了一个jar,JXL。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.study.jvm</groupId>
<artifactId>om-demo</artifactId>
<version>1.0.0</version>
<build>
<plugins>
<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本地仓库 -->
<!-- https://mvnrepository.com/artifact/com.dianping.cat/cat-client -->
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-client</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
</project>
代码语言:javascript复制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在做回收统计的时候真得会一个一个统计的。开发时,借鉴线程安全,接触到大数据的地方,就有泄露的可能,被反被执行,也有可能出现泄露。