【问题一】Jvm的体系结构:
Jdk 减 工具=jre,jre 减 类库=jvm
方法区和堆被所有线程共享的
Java栈(虚拟机栈)=白色 运行时数据区线程私有
线程私有,线程1份 2个线程 2份
虚拟机栈:存储当前线程运行方法所需的数据,指令,返回地址
包含main方法和所有运行的方法。
方法(栈帧)中包含局部变量表(this,八大基本数据类型+引用(地址 hotspot版本(句柄池) 直接指针))
栈帧包括操作数栈/动态链接(运行时的多态)/返回地址
本地方法栈native
存储当前线程运行native方法所需的数据,指令,返回地址
本地方法native 底层jvm使用C++实现的
程序计数器
当前线程正在执行的字节码指令的地址(行号)
线程私有,100个线程 虚拟机栈,本地方法栈 100份
Eg:机器cpu执行(16核)-->100个线程
GC的作用域------> 共享的区域
【问题二】常见的垃圾回收算法
- 引用计数
- 复制回收算法
- 标记清除
- 标记整理
1.引用计数法(应用:微软的COM/ActionScript/Python...)
缺点:
- 每次对对象赋值时均要维护引用计数器,且计数器本身也有一定的消耗;
- 较难处理循环引用
JVM的实现一般不采用这种方法(有对象引用加个1,没对象引用减个1)
2.复制回收算法
MinorGC的过程(复制->清空->互换)
1.eden、SurvivorFrom复制到SurvivorTo,年龄+1
首先,当Eden区满的时候会触发第一次GC,把还活着的对象拷贝到SurvivorFrom区,当Eden区再次触发GC的时候会自动扫描Eden区和From区域,对这两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到To区域(如果有对象的年龄已经达到了老年的标准,则复制到老老年代区),同时把这些对象的年龄+1
2.清空eden、SurvivorFrom
然后,清空Eden和SurvivorFrom中的对象,也即复制之后有交换,谁空谁是to
3.SurvivorTo和SurvivorFrom互换
最后,SurvivorTo和SurvivorFrom互换,原SurvivorTo成为下一次GC的SurvivorFrom区。部分对象会在From和To区域中复制来复制去,如此15次(由JVM参数MaxTenuringThreshold决定,这个参数默认是15),最终如果还是存活,就存入老年代
3.标记清除算法
算法分成标记和清除两个阶段,先标记处要回收的对象,然后统一回收这些对象。
4.标记整理算法
【问题三】JVM垃圾回收的时候如何确定垃圾?是否知道什么是GC Roots?
什么是垃圾?简单的来说就是内存中已经不再被使用到的空间就是垃圾。
要进行垃圾回收,如何判断一个对象是否可以被回收?
1.引用计数法;
2.枚举根节点做可达性分析(根搜索路径)
为了解决引用计数法的循环引用问题,Java使用了可达性分析的方法。
所谓“GC roots”或者tracing GC的“根集合”就是一组必须活跃的引用。
基本思路就是通过一系列名为“GC Roots”的对象作为起点,从这个被称为GC Roots的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。即给定一个集合的引用作为根出发,通过引用关系遍历对象图,能被遍历到的(可达性的)对象就被判定为存活,没有被遍历到的就被判断为死亡。
Java中可以作为GC Roots的对象
1.虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。
2.方法区中的类静态属性引用的对象。
3.方法区中常量引用的对象
4.本地方法栈中JNI(Native方法)引用的对象。
【问题三】JVM调优和参数配置,请问如何盘点查看jvm系统默认值
如何查看一个正在运行的Java程序,他的某个jvm参数是否开启,具体多少?
jps -l 查看运行的Java程序进程编号
jinfo -flag xxx java进程号 是否开启,具体多少
- JVM的参数类型
1.标配参数 -version -help java -showversion
2.X参数(了解) -Xint 解释执行 -Xcomp 第一次使用就编译成本地代码 -Xmixed 混合模式
3.XX参数
3.1 Boolean类型 公式-XX:+或者-某个属性值 +表示开启 -表示关闭
jinfo -flag PrintGCDetails 进程号
Case:是否打印GC收集细节 -XX:-PrintGCDetails -XX:+PrintGCDetails
3.2 KV类型
-XX:属性key=属性值value
Eg:-XX:MetaspaceSize=128m 初始空间大小
-XX:MaxTenuringThreadhold=15 垃圾回收到15次到老年区
3.3 jinfo举例,如何查看当前运行程序的配置
jinfo -flag 配置项 进程号 是否开启,具体多少
jinfo -flags 进程号 jvm所有的参数,包括系统的和自己修改过的
3.4 两个经典参数:-Xms和-Xmx 属于XX参数
-Xms:等价于-XX:InitialHeapSize 初始化堆内存
-Xmx:等价于-XX:MaxHeapSize 最大堆内存
-Xms 物理内存的1/64 默认
-Xmx 物理内存的1/4
2.盘点家底查看JVM默认值
1)查看参数盘点家底java -XX:+PrintFlagsInitial
主要查看修改更新java -XX:+PrintFlagsFinal =未修改的 :=修改之后的,jvm加载不一样,自己修改的
java -XX:+PrintFlagsInitial -version
java -XX:+PrintFlagsFinal -version 版本号
2) PrintFlagsFinal举例,运行Java命令的同时打印出参数。
修改元空间内存
3)java -XX:+PrintCommandLineFlags -version 偏重于看默认的垃圾回收器
盘点家底的命令
最后一个参数:7大GC垃圾回收机制的哪个,默认用的是哪个垃圾回收器,并行回收器
【问题四】平时工作用过的JVM常用基本配置参数有哪些
-Xss 栈管运行,堆管存储。Windows初始值为0
C:\DemoSpringboot>jinfo -flag ThreadStackSize 7308
-XX:ThreadStackSize=0
详解典型设置案例和PrintGCDetail
测试 -Xms10m -Xmx10m -XX:+PrintGCDetails
[GC (Allocation Failure) [PSYoungGen: 2048K->504K(2560K)] 2048K->942K(9728K), 0.0016903 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2560K:新生代总共内存
9728K:JVM堆的总空间大小
打印出
[Full GC (Allocation Failure) [PSYoungGen: 504K->0K(2560K)] [ParOldGen: 574K->967K(7168K)] 1078K->967K(9728K), [Metaspace: 3194K->3194K(1056768K)], 0.0070190 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
一般设置
堆内存最小 堆内存最大值 栈内存1024k 元空间512 看垃圾回收器 看GC回收的细节