首先我们自己写一个demo,来模拟内存溢出
新建User类;
private int id; private String name; byte[] a = new byte[1024*1000]; 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; } }
编写一个测试接口:
@RestController @RequestMapping("/jvm") public class IndexController { @RequestMapping("/user/process") public String processUserData() throws InterruptedException { ArrayList<User> users = queryUsers(); for (User user: users) { System.out.println("user:" + user.toString()); } return "end"; } /** * 模拟批量查询用户场景 * @return */ private ArrayList<User> queryUsers() { ArrayList<User> users = new ArrayList<>(); for (int i = 0; i < 1000; i++) { users.add(new User(i,"zhuge")); } return users; } }
把新建的项目打包上传到服务器,然后用下面的命令启动jar
java -Xmx512M -Xms512M -Xmn256M -Xss256K -XX:SurvivorRatio=6 \
-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M \
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC \
-XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly \
-XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/jvm/dump/ \
-jar fairy-jvm-1.0.jar
参数讲解:
-Xmx512M -Xms512M -Xmn256M 堆年轻代和老年代设置内存大小
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC 垃圾回收算法
-XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError 打印GC参数和内存溢出是dump
-XX:HeapDumpPath=/jvm/dump/ dump路径
然后调用接口模拟内存溢出,可以使用jmeter进行压测来模拟并发查看内存溢出时dump的文件,将dump的文件用jdk自带的工具jvisualvm查看
可以找到发生内存溢出的地方并进行修正,我们可以通过远程连接jvisualvm,来监控服务
java -Xmx512M -Xms512M -Xmn256M -Xss256K -XX:SurvivorRatio=6 \
-Dcom.sun.management.jmxremote.port=8888 \
-Djava.rmi.server.hostname=node01 \
-Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false \
-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M \
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC \
-XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly \
-XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/jvm/dump/ \
-jar fairy-jvm-1.0.jar
相比前面添加了一些参数,
-Dcom.sun.management.jmxremote.port=8888 为远程机器的JMX端口
-Djava.rmi.server.hostname=node01 为远程机器IP
-Dcom.sun.management.jmxremote.ssl=false ssl
-Dcom.sun.management.jmxremote.authenticate=false 认证
监控信息如下:
如果是tomcat部署,tomcat的JMX配置:在catalina.sh文件里的最后一个JAVA_OPTS的赋值语句下一行增加如下配置行
JAVA_OPTS="$JAVA_OPTS
-Dcom.sun.management.jmxremote.port=8888
-Djava.rmi.server.hostname=node01
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false"