(1)JVM体系结构面试简述

本文详细阐述了JVM的五大部分及其作用:类加载器、运行时数据区(包括方法区、本地方法栈、程序计数器、堆和虚拟机栈)、本地语言内存空间区别,以及内存中垃圾收集(GC)的触发条件,重点讲解了 Minor GC、Major GC和Full GC的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.JVM五大部分


(1)JVM五大部分作用简述

  1. 类加载器(Class Loader): 加载字节码文件到内存(次要)

  2. 运行时数据区(Runtime Data Area): JVM 核心内存空间结构模型(核心)其中方法区域和堆线程共享

  3. 执行引擎(Execution Engine): 对 JVM 指令进行解析,翻译成机器码,解析完成后提交到操作系统中。

  4. 本地库接口(Native Interface): 供 Java 调用的融合了不同开发语言的原生库。

  5. 本地方法库(Native Libraries): Java Native方法的具体实现。

2.运行时数据区五大部分


(1)方法区(共享)

  • 方法区存储虚拟机加载的类信息、常量/常量池(如String s="123")、静态/类变量(static)即时编译器编译后的代码等数据。
  • 方法区是一种规范,永久代是方法区的一种实现。
        永久代和元空间:JDK 7 以前字符串常量池放在永久代中的,将字符串常量池移动到了堆中。JDK 8 删除了永久代,改用元空间实现方法区,直接存在了计算机内存中。(因为堆内存大小固定若不足则需要手动扩充,降低系统稳定性)
        
        元空间Metaspace :存放类元数据。元空间和永久代是方法区的实现,方法区只是一种规范,在 Java 7 之后,原先位于方法区永久代里的字符串常量池已被移动到了 Java 堆中,因为永久代的内存空间极为有限,如果频繁调用 inter 方法,内存无法存储这么多数据。在 Java 8 之后将永久代完全删除了,使用元空间替代了永久代。 元空间使用本地内存,永久代使用 JVM 内存,所以使用元空间的好处在于程序的内存不在受限于 JVM 内存,本地内存剩余多少空间,元空间就可以有多大,解决了空间不足的问题。

(2)本地方法栈

  • 和虚拟机栈的作用和原理基本相同,都可以用来执行方法。不同点在于执行的是本地方法。
  • 本地方法的使用原理理解(如C语言):
    1. 在 Java 程序中声明 native 修饰的方法,只有方法定义,没有方法实现,将该 Java 文件编译成字节码文件
    2. 用 javah 编译字节码文件,生成一个 .h 文件。
    3. 写一个 .cpp 文件实现 .h 文件中的方法。
    4. 将 .cpp 文件编译成动态链接库文件 .dll 。
    5. 使用 System.loadLibrary() 加载动态连接库文件。
常用本地方法如: public final native Class<?> getClass()、public native int hashCode()、protected native Object clone()

(3)程序计数器

  • 占用内存空间较小,是当前线程所执行的字节码行号指示器,通过改变这个计数器的值来选取下一条需要执行的字节码指令。
  • 多个线程之间的程序计数器相互独立,互不影响,这保证了每个线程都恢复后都可以找到具体的执行位置

(4)堆(共享)

  • 存放实例化对象,占用大部分的空间,是 GC 的主要管理区域,又分为年轻代、老年代、永久代(JDK8以后去掉)。
  • 年轻代: 又可分为 Eden(伊甸),Survivor from,Survivor to
    1. Eden区:对象刚被创建的时候,存放在 Eden 区,如果 Eden 区放不下(触发MinorGC,复制算法),则放在 Survivor 区
    2. Survivor区: GC 回收时,将 Eden 存活的对象存入 Survior From 中。 下一次回收时,将 Survior From 中的对象存入 Survior To 中,清除 Survior From。然后重复步骤, Survior From 变成 Survior To,Survivor To 变成 Survivor From。每次回收时,对象年龄+1,增长到一定程度的对象进入老年代。(注:Survior区满了是不能用复制算法)
  • 老年代存放生命周期较长的对象(JDK 8 改用元空间替代永久代)老年代的空间也会不够用,最终会执行Major GC(MajorGC 的速度比 Minor GC 慢很多很多,据说10倍左右)。Major GC使用的算法是:标记清除(回收)算法或者标记压缩算法

(5)虚拟机栈(Java执行的内存模型)

  • Java Method执行的内存模型
  • Java 栈中存放的是多个栈帧,每个栈帧对应一个被调用的方法,主要包括局部变量表(局部变量)、操作数栈、动态链接、方法返回地址(方法出口)。每一个方法的执行,JVM 都会创建一个栈帧,并且将栈帧压入 Java 栈,方法执行完毕,该栈帧出栈。
        注:new创建的对象和数组存在堆中,而数组变量(或引用值存在堆中)

【本地语言内存空间区别】

  • 代码区≠方法区,其他都一样(原始语言如C的内存空间分布如下)

3.内存中GC触发条件


(1)MinorGC(堆Eden->survivor):From和To互换实现原理

    新生代Minor GC 复制算法: 把内存区域分为两块,每次使用一块,GC的时候把一块中的内容移动到另一块中,原始内存中的对象就可以被回收了。

  • 优点是避免内存碎片。

  • 缺点是内存满了不能使用

(2)MajorGC(堆survivor->older):标记清除或标记压缩

  • 标记清除:

    • 1. 首先会从GC root进行遍历,把可达对象(存过的对象)打标记

    • 2. 再从GC root二次遍历,将没有被打上标记的对象清除掉。

    • 优点:老年代对象一般是比较稳定的,相比复制算法,不需要复制大量对象。之所以将所有对象扫描2次,看似比较消耗时间,其实不然,是节省了时间。举个栗子,数组 1,2,3,4,5,6。删除2,3,4,如果每次删除一个数字,那么5,6要移动3次,如果删除1次,那么5,6只需移动1次。

    • 缺点:这种方式需要中断其他线程(STW),相比复制算法,可能产生内存碎片。

(3)FullGC(堆survivor->older):标记清除或标记压缩

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值