一、jvm的运行参数
jvm的标准参数,一般都是很稳定的,在未来的JVM版本中不会改变,可以使用java -help 检索出所有的标准参数。 通过以下命令查看:
命令:java -help
可以看到我们经常会用到的 -sever,-version等参数。
实战1:查看JVM版本
命令:java -version
jvm版本是1.8.0_202,而且是64位,server,混合模式。
实战2:通过-D设置系统属性参数
先写一段代码:
public?class?TestVM?{
????????public?static?void?main(String[] args) {
????????????????String name = System.getProperty("name");
????????????????if(name!=null){
????????????????????????System.out.println(name);
????????????????}
????????????????else{
????????????????????????System.out.println("ling");
????????????????}
????????}
}
运行上面这段代码,通过-D带入一个参数name,根据name的值进行判断如果name不为null,则打印,如果为null则打印 ling。
#?在root下创建一个文件夹下创建这个文件
vi TestJVM.java#把上面的java代码复制进去#执行代码
[root@localhost test]# javac TestJVM.java
[root@localhost test]# java TestJVM
ling#设置参数进行,设置系统属性:‐D<名称>=<值>
[root@localhost test]# java -Dname=smart哥
smart哥
jvm的-X参数是非标准参数,在不同版本的jvm中,参数可能会有所不同,可以通过java -X查看非标准参数。
jinfo是JDK自带的一种命令行工具,用于查看和修改Java应用程序的运行参数。它可以帮助开发人员在运行时调整JVM参数,例如堆大小、GC收集器、线程栈大小等
查Java进程25834的JVM参数
命令:jinfo -flags 25834
Non-default VM flags:非标准参数
Command line: 通过命令行设置的参数
查Java进程25834的单个JVM参数
命令:jinfo -flag ConcGCThreads 25834
jvm的内存模型在1.7和1.8有较大的区别,虽然本套课程是以1.8为例进行讲解,但是我们也是需要对1.7的内存模型有所了解,所以接下里,我们将先学习1.7再学习1.8的内存模型。目前线上常用版本组合是jdk8+tomcat8.5。
fullGC - 回收整个堆内存(年轻代、老年代)
JVM1.7和1.8的最大差异,1.7的永久区在堆内存(虚拟机)中,1.8永久区被废弃,加入了MetaData(位于机器直接内存(内存条)中,不在虚拟机中)
可能理由,永久区管理字节码文件,一般情况下,增加字节码文件,都会重启虚拟机,运行中垃圾回收期基本不用管理字节码文件,只有热部署的时候,永久区才会断追加字节码文件,这也就是为什么热部署容易报java.lang.OutOfMemoryError:PermGen space,也可能是导致永久区不再需要被虚拟机管理,在1.8被移除的一个重要原因,将字节码文件直接放入机器本地内存空间中(MetaData)。
jstat命令可以查看堆内存各部分的使用量,以及加载类的数量。
命令的格式如下:
jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]
命令:jstat -class 3694
命令:jstat -compiler 3694
命令:jstat -gc 3694
查看进程11005的GC信息 间隔1秒1次,打印5次
命令:jstat -gc 11005 1000 5
前面通过jstat可以对jvm堆的内存进行统计分析,而jmap可以获取到更加详细的内容。如:内存使用情况的汇总、对内存溢出的定位与分析。
命令:jmap -heap 3694
解释:
Java命令学习系列(三)——Jmap -腾讯云开发者社区-腾讯云
命令:jmap -histo 3331
命令:jmap -histo:live 25834| more
通过浏览器访问解析后的文件
如果有防火墙,开放8889端口
jhat还提供了查询功能,在页面的最后面
MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。
旧版本下载地址:Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation
内存溢出在实际的生产环境中经常会遇到,比如,不断的将数据写入到一个集合中,出 现了死循环,读取超大的文件等等,都可能会造成内存溢出。
如果出现了内存溢出,首先我们需要定位到发生内存溢出的环节,并且进行分析,是正 常还是非正常情况,如果是正常的需求,就应该考虑加大内存的设置,如果是非正常需求,那么就要对代码进行修改,修复这个bug,我们需要借助于jmap与MAT工具进行定位分析。
接下来,我们模拟内存溢出的场景。
编写代码,向List集合中添加100万个字符串,每个字符串由1000个UUID组成。如果程序能够正常执行,最后打印ok(idea编辑器中需要设置内存溢出相关参数)
#参数如下:
‐Xms8m ‐Xmx8m ‐XX:+HeapDumpOnOutOfMemoryError
package?com.zte.oom;
import?java.util.ArrayList;import?java.util.UUID;
/**************************************************
?*
?* @title qq184480602
?* @desc ling
?* @author smart哥
?*
?**************************************************/
public?class?TestOOM?{
????public?static?void?main(String[] args) {
????????ArrayList<String> stringArrayList = new?ArrayList<>();
????????for?(int?i = 0; i <1000000?; i++) {
????????????String str="";
????????????for?(int?j = 0; j <1000?; j++) {
????????????????str=str+UUID.randomUUID().toString();
????????????}
????????????stringArrayList.add(str);
????????}
????????System.out.println("it is over!!");
????}
}
#设置VM options:
-Xms8m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
大白话:
在VMOptions中设置-XX:+HeapDumpOnOutOfMemoryError,当出现堆栈溢出的时候,dumpJVM堆栈信息到java_pid32216.hprof文件,32216为程序在系统中的进程号。
运行一段时间后会抛出java.lang.OutOfMemoryError: Java heap space 异常。
可以看到,发生了内存溢出,此时会dump文件到java_pid13320.hprof文件中。
查看Leak Suspects视图
可以看到,有89.07%的内存由Object[]数组占有,所以比较可疑。 分析:这个可疑是正确的,因为已经有超过89%的内存都被它占有,这是非常有可能出现内存溢出的,一般达到60%-70%就可以确实是这引起的内存溢出了。 查看Object Details视图详情如下
查看Object Details视图
可以看到集合中存储了大量的uuid字符串。
继续查看dominator视图进一步验证。
查看dominator视图