JVM虚拟机模型学习

2022-11-01  本文已影响0人  蓝调_4f2b

引言

先上图


JVM结构.png

功能:存放局部变量(线程栈)

1. 栈帧

(1)概念
一个方法对应一块栈帧内存区域,该栈帧中保存方法中声明的局部变量


栈帧工作概念图.png

(2)栈帧结构
栈帧由局部变量表,操作数栈,动态链接,方法出口等部分组成。其中:
操作数栈:方法运行时,用于变量操作的临时内存,如运算(1 + 1 = 2)时在操作数栈分配的内存中完成,后复制给栈帧中的局部变量;
动态链接:运行时,将符号变为其代码对应的直接内存地址(直接引用);
例如:func()运行时,将方法区中对应逻辑地址拷贝入动态链接之中;
方法入口:返回main()栈帧;

2.程序计数器

(1) 概念:每一个线程独有的内存空间,存放每个线程即将执行的代码行号
(2) 作用:多线程场景下,当前线程CPU被抢占,挂起后由程序计数器记录的行号恢复程序


程序执行器概念图.png

3. 栈,方法区与堆关系

栈中对象通过指针指向其堆中分配地址
方法区中常保存常量,静态变量及类信息


栈,方法区与堆关系.png

4. 对象的创建及结构

对象创建流程.png

4.1 分配内存的方法:

(1)指针碰撞方法:
条件:当Java堆内存绝对整齐的排列时(较常见)

指针碰撞法.png
(2)空闲列表方式:
当java堆中已用内存不规整时,已使用的内存和空闲内存相互交错,无法使用指针碰撞方法,虚拟机中维持一个map,记录还有哪些内存块可用,有新对象要分配内存时,JVM分配map中的空闲内存块,并更新map中的信息。

5. 堆结构与垃圾收集

5.1 堆结构与垃圾收集结构图

堆结构与垃圾收集.png

注1: 一般老年代最后留存的对象为静态对象,在7*24小时web服务中,静态对象将一直存活
注2: 一个OOM(内存溢出)小案例

public class HeapTest {
  byte[] a = new byte[1024 * 100];
  public static void main(String[] args) {
    ArrayList<HeapTest> heapTests = new ArrayList<>();
    while(True) {
      heapTests.adds(new HeapTest());
     # 通过可达性分析方式不能回收该部分内存
    }
  }
}

5.2 对象的并发放入方式

在高并发web服务中,对象会尝试通过高并发的方式放入堆中分配的空间,其中有两种方式:
(1)Cas+失败重试方案
(2)本地线程分配缓冲(TLAB:JDK1.8默认方式)
JVM预先为每个线程分配对应的内存块

5.3 对象结构

(1)对象由对象头,实例数据及对齐填充组成


对象结构.png

(2)对象结构的优化:指针压缩(JDK默认:8字节对象压缩至4字节)

5.4 对象内存流程

对象内存流程.png

(1)对象逃逸现象及分析

例1:
User u = CreateUser();
public User CreateUser() {
  User user = new User();
  user.setId(1);
  return user;
}
// 局部对象user逃逸出了它的create方法,JVM视情况将这种对象的内存分配至堆中保存
例2:
public void CreateUser() {
  User user = new User();
  user.setId(1);
  return ;
}
//  该局部变量user未逃逸,对于该种情况,JVM将判断对象所占内存大小,若内存较小,将对象保存入方法createUser对应的栈桢中;
// 优点:该方法结束时,内存(栈桢)被销毁,该对象内存被回收,以这种方式降低GC频率

(2)JVM对象逃逸处理
JVM虚拟机通过参数(-XX:+DoEscapeAnalysis) JDK默认开启
标量替换:若栈桢中无连续空间放置对象,仅将对象中成员变量放入栈桢中


标量替换.png

标量替换参数:XX: +EliminateAllocations

5.5 对象的分配:

(1)对象主要在Eden区分配,当Eden区空间不足时触发一次minor GC
(2)大对象直接进入老年代(建议直接进入老年代,不然增加年轻代回收频率)
大对象定义: -XX : PretenureSize Threshold = 10000000(大对象对应阈值)
巧妙设计分代年龄:根据业务需要设置分代年龄,使对象不必经过15次GC才进入老年代区(-XX:MaxTenuringThreshold)

6. 老年代空间分配担保机制

老年代空间分配担保机制.png
注:在做gc之前,会判断老年代空间是否可存下eden区所有Obj,若存不下进行一次minor gc,通过老年代担保机制判断老年代剩余空间是否小于历史每次minor gc后进入OLD区对象平均大小,若不满足进行一次full gc。
优点:尽量减少做full gc的次数

7. 对象内存的回收

(1)引用计算方法:

main() {
  obj A  = new Obj();    // A计数值+1
  obj B = new Obj();
  A.instance = B;         // A计数+2
  B.instance = A;
}

A = null;    // A计数值-1

(2) 可达性分析
将GC roots对象作为起点,从此向下搜索引用对象,可找到的标为非垃圾对象,其余为垃圾对象.

根结点一般为:

8. 常见引用类型

9. 如何判断一个类已无用

回收元空间(方法区)内存:3个条件需均满足

上一篇 下一篇

猜你喜欢

热点阅读