JVM
JVM内存结构等
JavaJVM
70 views
Oct 08, 2024

#JVM内存结构

JVM内存空间分为5个部分:

  • 程序计数器(PC)
  • Java虚拟机栈
  • 本地方法栈
  • 方法区

image-20221120165035300

其中,程序计数器、本地方法栈、Java虚拟机栈时线程隔离的,堆区和本地内存时线程共享的。

##程序计数器(PC)

保存当前正在执行的字节码指令地址,程序代码每执行完成一条,PC就指向下一个需要被执行的字节码。

生命周期同线程生命周期

##Java虚拟机栈

Java虚拟机栈是描述Java方法运行过程的模型。

Java虚拟机栈为每个即将运行的Java方法创建一块区域(栈帧),栈帧用于保存方法运行过程中的信息。这些信息包括(局部变量表、操作数栈、动态链接、方法返回地址),当方法运行过程中需要创建局部变量时,就将局部变量的地址的值存入栈帧中的局部变量表中。Java虚拟机栈栈顶的栈帧是当前正在执行的活动栈,保存当前正在执行的方法的相关信息,PC也会指向这个地址。

栈的大小是JVM在编译时就确定的,不可变

每一个栈帧保存以下信息:

  • 局部变量表
  • 操作数栈
  • 动态链接
  • 方法返回地址

局部变量表

存放局部变量的表,一个数字数组,用于保存方法参数,方法体局部变量,基本数据类型,对象引用,returnAddress等。

局部变量表大小以槽(shot)为单位,64位数据占用两个槽(long、double),32位占用一个槽。

操作数栈

保存计算过程中的中间结果,计算过程中变量临时存储空间

动态链接

指向运行时常量池的方法引用

方法返回地址

方法正常退出或异常退出的地址


压栈与出栈

栈顶总是当前正在执行的方法,当当前执行的方法调用另一个方法时,另一个方法会入栈执行。当一个方法执行完,该方法出栈。如果该方法有返回值,那么该方法的返回值变成新方法栈帧操作数栈中的一个操作数。

##本地方法栈

本地方法栈时JVM为Java中Native方法准备的空间。同Java虚拟机栈一样,运行时会创建栈帧。

##

用于保存对象的空间,(几乎)所有对象都存放在堆中。

整个堆分为三个部分,新生代和老年代和元空间,新生代又分为三个部分(Eden、From Survivor、To Survivor)

年轻代

对象创建的地方。年轻代被分为三个区域,Eden,survivor0和survivor1区,比例8:1:1。当年轻代空间已满时,会触发MinorGC。

MinorGC:(to区一直为空,如果to区有from区没有,就叫唤to区和from区)

  • Eden区满,执行MinorGC,将Eden区幸存对象转移到survivor0区
  • 在survivor0区执行MinorGC,检查survivor0区,再次将幸存对象转移到survivor1区
  • 经过15次循环,仍然幸存的对象会被移动至老年代

老年代

年轻代存活次数较多的对象,当老年代空间满时,触发MajorGC

堆的特点:

  • 线程共享,整个JVM只有一个堆,所有线程共同访问这一个堆。
  • 垃圾回收的主要场所。

对象的分配过程

  • 逃逸分析
    • 根据逃逸分析的结果,判断对象是否可以在栈上生成
  • 判断是否为大对象
    • 如果是大对象,则在Eden区生成
  • 判断是否在TLAB中分配
    • TLAB(线程本地分配缓存区)

逃逸分析

将线程私有的对象在栈上生成,该对象在线程结束时自动销毁,不需要使用GC,同时栈上分配速度更快,提高性能,但栈内存大小有限,无法存放大对象。

当对象没有逃逸时,该对象在栈上生成同时该对象也拥有以下特性:

  • 锁消除

如果编译器确定该对象只在当前线程使用时,会消除该对象的同步锁。

  • 标量替换

如果一个对象不逃逸,则不用创建该对象,只需要在栈上创建该对象的成员标量。

TLAB(Thread Local Allocation Buffer)

JVM为每个线程分配的私有缓冲区域,在Eden区中。

##方法区

JDK7以前方法区在堆中,又称永久代,JDK8方法区在本地内存中的元空间。

方法区保存以下信息:

  • 类信息
  • 常量池
  • 静态变量
  • 即时编译器编译后的代码

方法区线程共享,方法区中的信息需要永久保存,所以方法区又称为永久代。

方法区中有运行时常量池

Java8 变化

  • 移除了永久代(PermGen),替换为元空间(Metaspace);
  • 永久代中的 class metadata 转移到了 native memory(本地内存,而不是虚拟机);
  • 永久代中的 interned Strings 和 class static variables 转移到了 Java heap;
  • 永久代参数 (PermSize MaxPermSize) -> 元空间参数(MetaspaceSize MaxMetaspaceSize)

取消永久代,类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆中

##直接内存(堆外内存)

#垃圾回收

##判断是否需要被回收

引用计数法

给对象添加一个引用计数器,当对象增加一个引用时计数器+1,引用失效时计数器-1,当引用计数为0时,此时该对象不被引用,可以判定为垃圾进行回收。循环依赖的对象引用计数永远不为0,引用计数法无法回收产生循环依赖的对象。

可达性分析法

以GC Roots(根对象)为起点进行搜索,能够到达的对象存活,不可到达的对象被回收。

##垃圾回收算法

标记清除

标记存活对象,清除未标记对象。

标记清除容易产生不连续内存碎片,导致无法为大对象分配内存

标记整理

标记存活对象,将存活对象向内存的一端移动,清除剩余未标记的对象。

复制算法

将内存空间分为两块,每次创建对象时只使用一块区域,当一块区域满之后,将这块区域上存活的对象全部复制到另一块内存,清除一块内存中所有对象。

复制算法在hotspot虚拟机上的应用在于,将堆内存分为了三分Eden区和两个survivor区,比例为8:1:1。每次使用Eden区和一个survivor区,内存利用率90%。垃圾回收时,先将Eden区和survivor0区对象复制到另一个survivor1区,在清除Eden区和survivor0区。

分代收集

堆内存被分为年轻代和老年代,在年轻代使用复制算法,在老年代使用标记清除和标记整理算法。

##MinorGC、MajorGC、FullGC

  • 部分收集(MinorGC和MajorGC)
    • 分为MinorGC和MajorGC,区域在年轻代和老年代
  • 整堆收集(FullGC)
    • 在堆和方法区收集

FullGC触发条件:

  • 调用了System.gc()方法
  • 老年代空间不足
  • 空间分配担保失败

#内存分配策略

  • 对象优先在Eden区分配:Eden区空间不足时进行MinorGC
  • 大对象在老年代生成
  • 长期存活对象移动到老年代:对象在Eden区每经过一次MinorGC年龄+1,年龄到达一定则移动到老年代
  • 动态判定对象年龄:如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代
  • 空间分配担保:执行MinorGC前,确定老年代最大连续可用空间是否大于Eden区所有存活对象大小总和,再执行MinorGC,如果不是则执行FullGC

#类的加载过程

加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载

  • 加载:查找并加载类的二进制数据
  • 验证:确保被加载的类正确
    • 文件格式验证
    • 元数据验证
    • 字节码验证
    • 符号引用验证
  • 准备:静态变量分配内存,并赋值
  • 解析:将常量池内的符号引用替换为直接引用
  • 初始化

#类加载器

  • 启动类加载器:Bootstrap ClassLoader
  • 扩展类加载器:Extension ClassLoader
  • 应用程序类加载器:Appliacation ClassLoader

#类加载机制

  • 全盘负责:当加载某个类时,同时加载该类所依赖和引用的类
  • 父类委托:优先使用父类加载器,父类加载器无法使用,再尝试从自己类路径中加载类
  • 缓存机制:缓存所有加载过的类,要使用某个类时,先从缓存中获取,没有在加载
  • 双亲委派机制:加载一个类时,将加载请求委托给父加载器完成,依次向上,直到传递到定增启动类加载器中。如果父加载器未找到需要的类,无法完成加载时,再使用子加载器加载。

##双亲委派机制加载过程

  1. 当AppClassLoader加载一个class时,将类加载请求委托给父类加载器ExtClassLoader。
  2. ExtClassLoader加载class时,将类加载请求委托给BootStrapClassLoader(启动类加载器)。
  3. 如果BootStrapClassLoader加载失败,使用ExtClassLoader加载。
  4. 如果ExtClassLoader加载失败,使用AppClassLoader加载。如果失败则报出ClassNotFoundException。
Total PV : 22920 UV : 4849
Copyright © 2024 陕ICP备2021015553号-2