JVM深入浅出(一)


文章目录

        • JVM的Server模式和Client模式的区别(了解)
        • 运行模式
        • JVM里的参数类型详解以及实操
        • jinfo命令详解以及实操
        • PrintFlags系列参数及实操
        • -Xmx 、-Xms、-Xss参数及实操
        • JVM运行时数据区
        • JVM的内存结构

JDK版本:1.8
官网:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
学JVM的终极目标:生产环境上的性能调优。
JVM的Server模式和Client模式的区别(了解) 后面讲的重点以Server模式为主。因为当Windows操作系统为32位时,JVM默认使用Client模式,如果是其它操作系统,当2G 2C以上默认是Server模式,低于这个配置是Client模式。一般64位都是Server模式。
JVM深入浅出(一)
文章图片

运行模式 Java有几种模式:
解释型int:这种模式不会把Java代码转换成本地代码
编译型comp:这种模式第一次会编译成本地代码,第一次会慢一点
混合型mixed:代码是解释还是编译交由JVM来处理
JVM里的参数类型详解以及实操 1)标准参数 稳定的
什么叫标准参数,举个例子:java -version 、java -help等等,这些参数是不会变的。标准参数和这些类似。从jdk1.0到现在,这一批参数几乎不会发生变化。
2)X参数 相对变化较少的
可能会变,但是变得又不多,比如:
JVM深入浅出(一)
文章图片

从上面可以看到加上-X有很多模式,解释模式去执行你的代码,编译模式去执行你的代码,混合模式去执行你的代码(这件事情是解释还是编译交由JVM来处理)。
那么Java是解释执行的还是编译执行的?不能确定,因为有个mixed混合执行。
再比如:
jdk7:有个东西叫永久代,在jdk8里面变成了Metaspace。发生了很大的变化。
3)XX参数 JVM调优的重点
XX参数分为:boolean布尔类型和非布尔类型。
举例:标准写法(boolean布尔类型)
-XX:[±]UseG1GC :表示把UseG1GC这个参数给启用或者禁用
还有一些参数是这样写(非布尔类):
-XX:MaxPermSize=64m :表示把MaxPermSize这个参数设置成64M
举个例子:
jps查看到某个pid(jps命令是查看Java进程用的),然后ps -ef查看这个pid的相关信息,可以看到很多相应的参数设置,如下:(jinfo -flags 直接跟pid可以列出所有的)
JVM深入浅出(一)
文章图片

用PrintGCDetails这个参数再举个例子:
用IDEA开发一段代码:
JVM深入浅出(一)
文章图片

按照下面方式可以看到,并没有启用PrintGCDetails这个参数。
JVM深入浅出(一)
文章图片

怎么启用这个参数?
找到下面这个页面,并在VM Options里面设置:-XX:+PrintGCDetails
JVM深入浅出(一)
文章图片

再启动代码,可以看到现在已经启动了这个参数:
JVM深入浅出(一)
文章图片

再看IDEA控制台,已经把GC相关信息打印出来了:
JVM深入浅出(一)
文章图片

再比如:如何查看某个进程使用的什么GC ?
可以这样看,先查到这个进程的进程号,然后可以这样:
jinfo -flag UseG1GC 进程号
jinfo -flag UseParallelGC 进程号
jinfo -flag UseConcMarkSweepGC 进程号

可以看一下这个进程使用了那种GC。下面用了UseParallelGC这种垃圾回收。
JVM深入浅出(一)
文章图片

上面是布尔类型,下面是非布尔类型
比如:-XX:MetaspaceSize参数
JVM深入浅出(一)
文章图片

可以看大MetaspaceSize是20多M,加入现在想把它设置大一点,设置成128M,如何设置?和上面类似。在这个地方加上-XX:MetaspaceSize=128m
JVM深入浅出(一)
文章图片

启动代码,再看它已经变成了128M
JVM深入浅出(一)
文章图片

jinfo命令详解以及实操 看帮助:
JVM深入浅出(一)
文章图片

举例:
JVM深入浅出(一)
文章图片

如下:
//这个是默认参数 Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2124414976 -XX:MaxNewSize=707788800 -XX:MetaspaceSize=134217728 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44564480 -XX:OldSize=89653248 -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC//这个是IDEA中自己设置的参数 Command line:-XX:+PrintGCDetails -XX:MetaspaceSize=128m -javaagent:D:\JetBrains\IntelliJ IDEA Community Edition 2018.2.8\lib\idea_rt.jar=54178: D:\JetBrains\IntelliJ IDEA Community Edition 2018.2.8\bin -Dfile.encoding=UTF-8

PrintFlags系列参数及实操 -XX:+PrintFlagsInitial
-XX:+PrintFlagsFinal
在命令行输入:java -XX:+PrintFlagsInitial 回车后会有很多初始化参数。
JVM深入浅出(一)
文章图片

= 是默认值
:= 是修改过的
-Xmx 、-Xms、-Xss参数及实操 -Xmx 、-Xms、-Xss这三个参数是属于XX参数类型里面的。
其中-Xms 就相当于 -XX:InitalHeapSize(JVM初始化堆大小)
-Xmx 就相当于 -XX:MaxHeapSize(JVM最大堆大小)
-Xss 就相当于 -XX:ThreadStackSize(JVM线程)
-XX:InitalHeapSize:这个JVM初始化堆大小占电脑的memory的1/64,如果电脑是12G内存,那么它差不多是200M。
-XX:MaxHeapSize:这个JVM最大堆大小占电脑的memory的1/4,如果电脑是12G内存,那么它是3G。
-XX:ThreadStackSize:和环境有关。
**生产上的最佳实践,一般设置InitalHeapSize等于MaxHeapSize。**最小的和最大的是相等的。
JVM运行时数据区
运行时数据区必看文档:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

通过两个图来说明一下:
JVM深入浅出(一)
文章图片

JVM深入浅出(一)
文章图片

JVM运行时数据区中,有些区是JVM启动时就被创建,JVM退出时被销毁,跟随JVM,另外一些区是每个线程都有的,线程创建它就被创建,线程退出它就退出,跟随线程。
1.The pc Register:pc计数器。
不是重点。
2.Java Virtual Machine Stacks:Java虚拟机栈。
每个线程都有它自己的Java虚拟机栈,伴随着线程被创建。像抛出异常的时候,那些信息就是虚拟机栈里面打印出来的。
3.Heap:堆(重点)。
JVM的Heap(堆)是所有JVM线程所共享的。它是在JVM虚拟机启动的时候被创建。
Heap里面装的是:对象实列和数组(class instances and arrays)。
Heap里面存储的对象,由自动存储管理系统回收,这就是总所周知的GC垃圾回收,用垃圾回收器来进行管理。
举例:
你现在创建了一个class User。
然后在另一个地方new一个:User user = new User();
前面user是引用,后面new User()是对象,这个对象放在哪里?就放在Heap里面。
可以根据实现者的系统需求来选择合适的垃圾回收器。
堆可以是固定大小的,也可以根据计算需要进行扩展,如果不需要更大的堆,则可以收缩堆。堆的内存不需要是连续的。
如果计算需要的堆比自动存储管理系统提供的堆多,Java虚拟机将抛出OutOfMemory错误。
4.Method Area 方法区
JVM的方法区也是所有JVM线程所共享的。它并不是堆里面的。
方法区在jdk1.8里面就是那个Metaspace。
It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
方法区存储每个类结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括在类和实例初始化以及接口初始化中使用的特殊方法。
User user = new User();
引用 对象
定义了一个User类,会有User.class文件,它就存储在方法区里面,就是Metaspace里面。
上面引用user是在栈里面,对象new User()是在堆里面。
方法区和堆是GC调优的重点
方法区和堆都能存东西,但是存的东西是不一样的。
方法区存的是class等,堆存的是对象。
5.Run-Time Constant Pool 运行时常量池
不是重点。
6.Native Method Stacks 本地方法栈
JVM的内存结构 在jdk1.8里面,有两大区域,堆和非堆。
JVM堆内存空间分为两个区域:新生代(Young generation)和老生代(Old generation)。新生代用以保存生存周期短的对象,而老生代则是保存生存周期长的对象。
新生代区域被进一步划分为三个子区域:Eden,Survivor0,Survivor1。
JVM深入浅出(一)
文章图片

s0也叫from,s1也叫to。
so和s1大小都是一样的,在同一个时间点,只有一个是开启的,可用的,另外一个是空的,可以理解为主备。大部分情况下都是:User user = new User(); new一个对象首先放在Eden区,如果Eden区满了,就进行垃圾回收,如果对象还活着就放到s0区。每一次垃圾回收,会把Eden区和s0区的活的对象放到s1区,把其他的给清掉,这个时候Eden区和s0区就会空下来。每次回收都会有个年龄age的增加,每次加1。某个对象每次加1,当达到了某个限定值,就会被放到老年代区。前面是小GC,如果最终如果老生代也快满了,full GC(全局GC)就会启动。
Spark GC调优的目标就是确保老生代(Old generation )只保存生命周期长的RDD,而同时新生代(Young generation )的空间又能足够保存生命周期短的对象。这样就能在任务执行期间,避免启动full GC来收集任务执行期间创建的临时对象。
非堆区:
ccs:CompressedClassPointers压缩类指针
短指针:32位
长指针:64位
如果开启了ccs,就会使用短指针。
每new一个对象都会放在堆里面,每new一个对象有指向自己的class的指针,class是在方法区MetaSpace里面的。如果是在64位的环境下,指针是64位的,考虑到性能,有时候可以修改成32位的短指针。
【JVM深入浅出(一)】CodeCache:跟JIT、jni有关系。如果编译了本地代码就在这里,如果没有编译就不在。

    推荐阅读