我们回想一下对象进入老年代的几种方式:
- 大对象(代码排除没有大对象)
- 对象到达一定年龄阈值(通过Young GC观察没有达到15次)
- 动态对象年龄判断(Young GC后的存活对象小于Survivor区域的50%)
-Xms1536M -Xmx1536M -Xmn1024M -Xss256K -XX:SurvivorRatio=6 -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSInitiatingOccupancyOnly可以通过jinfo查看JVM参数是否生效,优化后的内存模型为:
文章插图
优化后我们再重新跑一下程序,新的gc变化:
优化完发现没什么变化,反而是Full GC次数还变多了 。
文章插图
我们思考下full gc 比minor gc还多的原因有哪些?
1、元空间不够导致的多余full gc
2、显示调用System.gc()造成多余的full gc , 这种一般线上尽量通过-XX:+DisableExplicitGC参数禁用,如果加上了这个JVM启动参数,那么代码中调用System.gc()没有任何效果
3、老年代空间分配担保机制
可以简单排除掉前2个原因,第三个老年代空间担保机制也可以通过观察minor gc 与full gc的次数比例进行排除,那接下来就可能真的就是程序产生了很多占内存的对象 。我们可以通过jmap、jvisualvm来跟踪到占内存的对象 。
jmap -histo 27808
文章插图
查到了有大量User对象生成,这个可能是问题所在,但不确定 , 还必须找到对应的代码确认,如何找到对应的代码有如下几种方式:
1、代码里全文搜索生成User对象的地方(适合只有少数几处地方的情况)
2、如果生成User对象的地方太多,无法定位具体代码 , 我们可以同时分析下占用cpu较高的线程,一般有大量对象不断产生,对应的方法代码肯定会被频繁调用 , 占用的cpu必然较高,参考上一篇https://www.cnblogs.com/process-h/p/16879018.html
最终定位到的代码如下:
@RestControllerpublic class IndexController { @RequestMapping("/user/process") public String processUserData() throws InterruptedException { ArrayList<User> users = queryUsers(); for (User user: users) { //TODO 业务处理 System.out.println("user:" + user.toString()); } return "end"; } /** * 模拟批量查询用户场景 * @return */ private ArrayList<User> queryUsers() { ArrayList<User> users = new ArrayList<>(); for (int i = 0; i < 5000; i++) { users.add(new User(i,"zhuge")); } return users; }}public class User { private int id; private String name; // 1024B * 100 = 100KB byte[] a = new byte[1024*100]; public User(){} public User(int id, String name) {super();this.id = id;this.name = name; } public int getId() {return id;} public void setId(int id) {this.id = id;} public String getName() {return name;} public void setName(String name) {this.name = name;}}发现User类中定义了一个byte[] a 成员变量,占了100KB,在queryUsers()中,一次性在内存中添加了500M的对象数据,明显不合适,需要根据上述中的运行时内存数据区域阈值进行优化 , 尽量消除这种朝生夕死的对象导致的full GC.
推荐阅读
- MySQL数据库的性能分析 ---图书《软件性能测试分析与调优实践之路》-手稿节选
- JVM调优工具使用手册
- JVM运行时数据区域详解
- JVM学习笔记——内存模型篇
- 星之彼端最强阵容搭配思路参考攻略
- jvm双亲委派机制详解
- 万字详解JVM,让你一文吃透
- JVM学习笔记——类加载和字节码技术篇
- 航海王热血航线欢乐海钓玩法思路是什么
- 炉石传说怎么打巫妖王(炉石传说打巫妖王思路)