JVM模式
- client模式,默认32位的Windows系统都采用这种模式
- server模式,只要是32位的其他系统,高于2G,2Core的都采取这种模式,现在基本都是server模式了
类型
- 解释型int,不会把Java代码转变为本地代码
- 编译型compile,会编译成本地代码,所以第一次编译会慢一点
- mixed mode 就是让JVM来决定我们的代码编译成哪种类型
-Xcomp这个参数传进来之后就会让我们的执行变成了编译型的
JVM参数类型
JVM参数类型有以下三种
- 标准
- X
- XX
标准参数是比较稳定的参数,从最初的版本到现在,这些参数都存在,版本几乎没有发生什么变化。比如说:java -version
X和XX参数在JDK的各个版本中可能会发生变化,其中,X参数是变化相对较小的,XX参数在JVM的调优是至关重要的
Q:JDK7到JDK8发生了一个什么最大的变化?
A:JDK7有一个永久代,JDK8变成了Metaspace
对于X参数和XX参数而言,又分为两种
- boolean -XX: [+/-] name
-XX: +UseG1GC -XX: -UseG1GC
+ 表示启用,-表示禁用 - 非boolean -XX:name=value
先介绍两个命令
- jps => pid
- jinfo -flag name pid
对于boolean类型的参数
先把作业停掉,然后点击IDEA最上方的Edit Configurations...
点击运行
从上图可以看出,我们通过在IDEA修改PrintGCDetails这个参数,程序运行的时候这个参数就启用了
我们再来看看另外一个参数UseG1GC
从上图可以看出,JDK8没有使用G1作为垃圾回收器
对于非boolean类型的参数
现在调整一下MetaspaceSize这个参数
运行
新生代到老年代,每一次GC都有一个年龄的控制,默认的年龄是15,如下图
那现在来修改一下这个参数-XX:MaxTenuringThreshold=16
一运行,直接报错
-XX:MaxTenuringThreshold这个参数不同版本是不一样的
jinfo命令
在命令行看看jinfo的用法
这里在使用jinfo -flags的时候有个问题
网上说Mac的话只要换高版本的JDK就能解决问题,这里就先不换了
我们使用Linux看一下这个命令
PrintFlags系列参数
- -XX:+PrintFlagsInitial
- -XX:+PrintFlagsFinal
java -XX:+PrintFlagsInitial
从控制台打印的结果来看
- =是默认值
- :=就是已经被修改过的
Xmx Xms Xss参数
特殊的XX参数
- -Xmx JVM堆的最大值 -Xmx = -XX:MaxHeapSize
- -Xms JVM堆的最小值 -Xms = -XX:InitialHeapSize
- -Xss 线程堆栈的大小 -Xss = -XX:ThreadStackSize
最佳实践:-Xmx和-Xms这两个参数一般设置成一样
使用jinfo查看InitialHeapSize和MaxHeapSize两个参数
默认情况下,JVM中MaxHeapSize的大小为总内存的1/4,InitialHeapSize的大小为总内存的1/64,我机器的内存是8G
思考:当出现-XX:ThreadStackSize=0,这是为什么?
提示:这个参数跟系统,JDK版本都是有关系的。
JVM运行时数据区
运行时数据区是一个规范,内存结构是一个实现
class User() {
String name;
public void eat() {}
}
User user = new User()
对于上面的代码,等号左边是引用,右边是对象,对象是存放在Heap里面
方法区是存放class信息,包括常量值等,也可以存对象,在JDK1.8里面就是MetaSpace
User.class是在MetaSpace里
引用是在栈里面
JVM内存结构
当new了一个User出来,首先会分配到Eden区,如果Eden区满了,就会进行垃圾回收,如果对象还活的,就会丢到s0上去,每一次GC就是做一个倒腾的过程,每一次倒腾的过程是有一个年龄的,每一次age + 1,如果age到了15岁,对象就会进入老年代。
ccs CompressedClassPointer 压缩类指针,如果开启了ccs,意味着使用的是短指针,短指针是32位的,默认的是长指针(64位),如果没有开启,ccs这部分是不存在的。
每new一个对象,都会有指向自己class的指针,class是在MetaSpace里,考虑到性能,有时候可以改成32位的,改了之后就是一个短指针