面试题之JVM内存结构

JVM 可以分为 5 个部分,分别是:

类加载器(Class Loader):加载字节码文件到内存。

运行时数据区(Runtime Data Area):JVM 核心内存空间结构模型。

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

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

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

JVM 的结构如下图所示:
在这里插入图片描述

这其中最复杂的是运行时数据区,它也是 JVM 内存结构最重要的部分。运行时数据区又可以分为方法区、虚拟机栈、本地方法栈、堆以及程序计数器,并且方法区和堆是线程共享的,虚拟机栈、本地方法栈、程序计数器是线程隔离的。下面详细讲解运行时数据区的各个组成部分。

1.线程共享

方法区:方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。

:该区域是所有线程共享的,存放几乎所有的对象实例。jvm管理的内存中最大的一块,也是GC收集器主要管理的区域。按回收内存的角度可以分为新生代,老年代和永久代;再细分的话有Eden空间,From survior,To survior空间;不管如何划分都是为了更好的回收内存,存储的也是对象实例。

新生代:新生代又可分为 Eden,from Survivor,to Survivor。Eden 区用来存放刚刚创建的对象,如果 Eden 区放不下,则放在 Survivor 区,甚至老年代中。Survivor 区又可分为 Survivor From 和 Survivor To,GC 回收时使用,将 Eden 中存活的对象存入 Survior From 中,下一次回收时,将 Survior From 中的对象存入 Survior To 中,清除 Survior From ,下一次回收时重复此步骤,Survior From 变成 Survior To,Survivor To 变成 Survivor From,依次循环,同时每次回收,对象的年龄都 +1,年龄增加到一定程度的对象,移动到老年代中。

老年代:存放年龄大的对象

永久代:jdk7之前就是用永久代来实现方法区,本质上来讲两者并不等价,仅因为Hotspot将GC分代扩展至方法区,所以将其称为永久代。在物理内存上是和堆是连续的但逻辑上是隔离的;jdk8后移除了永久代,用元空间代替。使用的是本地内存,这样减少了内存溢出的问题。
在这里插入图片描述

2.线程私有

本地方法栈:栈中方法都是用native修饰的,这些方法在Java中只有定义没有具体实现。

  • 由javah命令从.class文件转换成.h文件(头文件,里面包含函数原型和宏定义)
  • 用.cpp文件实现 .h 文件中的方法
  • 将 .cpp 文件编译成动态链接库文件 .dll
  • 使用 System.loadLibrary() 加载动态连接库文件

调用native方法的基本原理是利用反射机制,在运行时找到 .dll 文件并且解析,根据动态链接库中的文件名称创建出对象和方法,然后就可以利用对象调用方法了。

虚拟机栈:实际上,Java 虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。

局部变量表主要存放了编译器可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。

Java 虚拟机栈会出现两种错误:StackOverFlowError 和 OutOfMemoryError。

  • StackOverFlowError: 若 Java 虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。
  • OutOfMemoryError: 若 Java 虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出 OutOfMemoryError 错误。

程序计数器:它是一块较小的空间,可以看做当前线程执行字节码的行号指示器。字节码解释器通过改变计数器的值来选取下一条需要执行的字节码指令。
   另外,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。它也是jvm内存里唯一一个不会出现OOM的区域。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些常见的 JVM 面试及其解答: 1. 什么是 JVM? - JVM(Java 虚拟机)是 Java 程序的运行环境,它负责将 Java 字节码解释或编译为机器码并执行。 2. JVM 的主要组成部分有哪些? - JVM 主要由类加载器、运行时数据区域、执行引擎和本地库接口等组成。 3. 类加载器的作用是什么? - 类加载器负责将字节码文件加载到内存中,并生成对应的 Class 对象。 4. 运行时数据区域包括哪些部分? - 运行时数据区域包括方法区、堆、栈、程序计数器和本地方法栈等。 5. 什么是垃圾回收(Garbage Collection)? - 垃圾回收是指自动回收不再使用的内存资源,以便给其他对象使用,从而减少内存泄漏和提高程序性能。 6. 垃圾回收算法有哪些? - 常见的垃圾回收算法有标记-清除算法、复制算法、标记-整理算法和分代收集算法等。 7. JVM 中的方法区是用来存储什么信息的? - 方法区主要用于存储类的结构信息、常量池、静态变量和常量等。 8. JVM 内存模型中的栈和堆有什么区别? - 栈用于存放局部变量和方法调用,是线程私有的;堆用于存放对象实例和数组,是线程共享的。 9. JVM 的 JIT 编译器是什么? - JIT(Just-In-Time)编译器是一种动态编译器,它将热点代码(频繁执行的代码)编译为本地机器码,以提高程序的执行效率。 以上是一些常见的 JVM 面试及其解答,希望能对您有所帮助。如果您还有其他问,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值