JVM篇--Java内存区域高频面试题

这篇具有很好参考价值的文章主要介绍了JVM篇--Java内存区域高频面试题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

java内存区域

1 Java 堆空间及 GC?

首先我们要知道java堆空间的产生过程: 即当通过java命令启动java进程的时候,就会为它分配内存,而分配内存的一部分就会用于创建堆空间,而当程序中创建对象的时候 就会从堆空间来分配内存,所以堆空间存放的主要是对象和数组;
而GC 其实说白了就是java虚拟机回收对象的机制,即回收无效对象的内存用于将来的分配。

2 JVM 的主要组成部分及其作用?

JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。
那么他们分别有啥作用呢?
首先看Class loader:根据给定的全限定名类名(如:java.lang.Object)来装载class文件到Runtime data area中的method area。其实说白了就是类加载器,简单点-作用就是通过类加载器将编译好的class文件加载到运行时数据区
Execution engine(执行引擎): 执行class中的指令
Native Interface(本地接口):与native libraries交互,是其它编程语言交互的接口。
Runtime data area(运行时数据区域):这就是我们常说的JVM的内存

整体的过程:首先会通过编译器把Java代码转换成字节码源文件,之后类加载器会把字节码文件加载到内存中,即加载到运行时数据区,
但是其实字节码文件只是JVM的一套指令集规范,并不能直接交给底层操作系统来去执行,因此需要特定的命令解析器即执行引擎,将字节码翻译成底层的系统指令,再交由CPU去执行
同时java代码中 可以调用其他语言的本地库接口,进行一些系统调用或者c函数的调用
JVM篇--Java内存区域高频面试题,JVM,面试,jvm,java,开发语言

3 说说JVM 运行时数据区? 或:说一下JVM内存模型?

jvm内存模型大致被划分为如下几个区域:
程序计数器:也就是当前线程所执行的字节码指令的行号指示器,说白了就是当前字节码执行到的位置,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令

java虚拟机栈:用于存储方法执行时的局部变量表、操作数栈、动态链接、方法出口等信息,也是线程私有的。每个方法在执行时都会创建一个栈帧,栈帧包含了方法的局部变量表、操作数栈等信息。

本地方法栈:与 Java 虚拟机栈类似,只不过虚拟机栈是服务 Java
方法的,而本地方法栈是为虚拟机调用 Native 方法服务的

堆:用于存储对象实例和数组,它也是jvm中最大的一块内存区域,同时也是线程共享的,而堆包括年轻代和老年代,以支持垃圾回收机制。

  1. 年轻代(Young Generation):用于存放新创建的对象。年轻代又分为 Eden 区和两个 Survivor 区(通常是一个 From 区和一个 To 区),对象首先被分配在 Eden 区,经过垃圾回收后存活的对象会被移到 Survivor 区,经过多次回收后仍然存活的对象会晋升到老年代。
  2. 老年代(Old Generation):用于存放存活时间较长的对象。老年代主要存放长时间存活的对象或从年轻代晋升过来的对象。

方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据

4 什么是堆内存?

以Hotspot为例,堆内存主要由GC模块进行管理和分配,可以分为新生代和老年代,而新生代又可以分为eden区,s1区和s2区,并且他们的比例默认为8:1:1, 同时新生代和老年代的占比如下图所示
JVM篇--Java内存区域高频面试题,JVM,面试,jvm,java,开发语言
在使用堆内内存(on-heap memory)的时候,完全遵守JVM虚拟机的内存管理机制,采用垃圾回收器(GC)统一进行内存管理,
GC会在某些特定的时间点进行一次彻底回收,也就是Full GC,GC会对所有分配的堆内内存进行扫描,在这个过程中会对JAVA应用程序的性能造成一定影响,还可能会产生Stop The World。

5 什么是非堆内存?

通常来说方法区是非堆内存,而jdk1.8之前的方法区实现是永久代,而jdk1.8之后的方法区实现叫元空间

6 什么是堆外内存呢?

堆外内存, 常常又叫做直接内存。 和堆内内存相对应,堆外内存就是把内存对象分配在Java虚拟机的堆以外的内存
这些内存直接受操作系统管理(而不是虚拟机),这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。
具体实现 可以 用java.nio.DirectByteBuffer对象进行堆外内存的管理和使用
那么堆外内存的优点是什么?
减少垃圾回收:因为垃圾回收会暂停其他的工作。
加快复制速度:堆内在flush到远程时,会先复制到直接内存(非堆内存),然后在发送;而堆外内存相当于省略掉了这个工作。

7 永久代和方法区又有什么区别呢?

方法区是《Java虚拟机规范》中定义的内存区域,用于存储类的结构信息(如类的字节码、常量池、字段和方法信息等),
而 Java 默认虚拟机 HotSpot 中,在 JDK 1.8 之前的版本中,是通过永久代来实现方法区的,但 JDK 1.8 之后,永久代被元空间(Metaspace)取代。
所以,总结来看,方法区是规范,而永久代(和元空间)是具体实现。

8 那么为啥用元空间来取代永久代呢?

主要原因有以下几点,

  1. 兼容JRockit --首先java官方要收购JRocket,而JRockit 中没有“永久代”的概念 所以为了更好的融合JRockit和Hotspot源码,因此取消了永久代。
  2. 其次可以提高稳定性,降低OOM的风险-因为对于永久代来说是需要设置PermSize 和 MaxPermSize 参数的,而一旦这两个值设置的不合理或者设置的过小就会频繁触发FullGC 和导致 OOM(Out of Memory,内存溢出),但是当使用元空间来替代永久代后 出现OOM的风险就大大降低了,因为元空间使用的是本地内存,也就是只和本地内存大小有关。
  3. 降低运维成本–因为用了元空间后就不在需要运维或者开发人员手动的来去设置和调整元空间的大小

9 为什么调整字符串常量池的位置?

其实主要是为了提高回收效率,便于及时的回收常量池内存,同时也是会缓解永久代空间不足的问题
首先我们要知道字符串常量池在1.7之前是放到永久代的,而永久代的回收效率是很低的,只有在fullGC的时候才会触发,而fullGC的触发也是需要再老年代的空间不足,或者永久代不足时才会进行触发,这样就导致了字符串常量池的回收效率并不高。但其实在真正的开发中,我们一般会有大量的字符串常量被创建,回收效率低反过来也会导致永久代空间不足
因此在jdk1.7之后字符串常量池被放到了堆空间中,便于及时的回收内存

10成员变量、局部变量、类变量分别存储在内存的什么地方?

  1. 类变量
    类变量是用static修饰符修饰,定义在方法外的变量,随着java进程产生和销毁。在java8之前把静态变量存放于方法区,在java8时存放在堆中

  2. 成员变量
    成员变量是定义在类中,但是没有static修饰符修饰的变量,随着类的实例产生和销毁,是类实例的一部分
    由于是实例的一部分,在类初始化的时候,从运行时常量池取出直接引用或者值,与初始化的对象一起放入堆中

  3. 局部变量
    局部变量是定义在类的方法中的变量
    在所在方法被调用时放入虚拟机栈的栈帧中,方法执行结束后从虚拟机栈中弹出,所以存放在虚拟机栈中

11 堆和栈有什么区别?

具体区别可以看以下几点
1 存放的内容
堆存放的是对象的实例和数组,而栈存放的是局部变量,操作数栈
2 再从是否私有来看
堆对于整个应用程序来说都是共享的,而栈是线程独享,所以也是线程私有。他的生命周期和线程相同
3 物理结构
堆的物理地址分配对对象是不连续的。因此性能慢些。在GC的时候也要考虑到不连续的分配,所以有各种算法。
栈使用的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快。

12 什么是双亲委派模式?

说到双亲委派模式 我们先聊下什么是类加载器 以及类加载器的分类
类加载器(Class Loader)是 Java 虚拟机(JVM)的重要组成部分,负责将字节码文件加载到内存中并转换为可执行的类
而类加载器大致可以分为四种
启动类加载器:加载 JDK 中 lib 目录中 Java 的核心类库,即$JAVA_HOME/lib目录。
扩展类加载器:加载 lib/ext 目录下的类;
应用程序类加载器:加载我们写的应用程序;
自定义类加载器:根据自己的需求定制类加载器。

而 双亲委派模型是 Java 类加载器的一种工作机制。
它是指当一个类加载器需要加载一个类时,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无 法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。
双亲委派模型的优点是啥?
避免重复加载类:比如 A 类和 B 类都有一个父类 C 类,那么当 A 启动时就会将 C 类加载起来,那么在 B 类进行加载时就不需要在重复加载 C 类了。
提高安全性使用双亲委派模型也可以保证了 Java 的核心 API 不被篡改,如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类,而有些 Object 类又是用户自己提供的因此安全性就不能得到保证了。

那么如何打破双亲委派机制呢?
1.自定义类加载,重写loadclass方法
因为双亲委派的机制都是通过这个方法实现的,这个方法可以指定类通过什么类加载器来进行加载,所有如果改写他的加载规则,相当于打破双亲委派机制

2.使用线程上下文类
双亲委派模型的第二次“破坏”是由这个模型自身的缺陷所导致的,双亲委派很好的解决了各个类加载器的基础类统一问题,基础类之所以“基础”,是因为他们总被用户代码所调用,但是如果基础类又要重新调用用户代码,那咋办?
比如说JNDI是java的标准服务,它的代码是由启动类加载器进行加载的,但是jndi的作用就是进行资源的集中管理和查找,它需要调用由开发人员开发在classpath下的类代码,但是启动类加载器不会进行加载。
所以引入线程上下类加载器,通过java.lang.Thread类的setContextClassLoader()方法进行设置。如果创建线程是还未设置,它会从父线程继承一个,如果在应用程序全局范围内没有设置,那么这个线程上下类加载器就是应用程序类加载器。
那么这样JNDI服务使用这个线程上下类加载器去加载所需的spi代码,也就是父类加载器请求子类加载器去完成类加载的动作,这个实际是打通了双亲委派的逆向层次结构。文章来源地址https://www.toymoban.com/news/detail-790076.html

到了这里,关于JVM篇--Java内存区域高频面试题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 深入理解 JVM 之——Java 内存区域与溢出异常

    深入理解 JVM 之——Java 内存区域与溢出异常

    更好的阅读体验 huge{color{red}{更好的阅读体验}} 更好的阅读体验 本篇为深入理解 Java 虚拟机第二章内容,推荐在学习前先掌握基础的 Linux 操作、编译原理、计算机组成原理等计算机基础以及扎实的 C/C++ 功底。 该系列的 GitHub 仓库:https://github.com/Doge2077/learn-jvm Java 虚拟机在

    2024年02月09日
    浏览(11)
  • JVM零基础到高级实战之Java内存区域本地方法栈

    JVM零基础到高级实战之Java内存区域本地方法栈 JVM零基础到高级实战之Java内存区域本地方法栈 本地方法栈是什么? 用于作用域本地方法执行的一块Java内存区域 为什么要有本地方法栈? 与Java虚拟机栈相同,每个方法在执行的同时都会创建一个栈帧(Stack Framel)用于存储局部

    2024年02月09日
    浏览(4)
  • java八股文面试[JVM]——JVM内存结构

    java八股文面试[JVM]——JVM内存结构

    参考: JVM学习笔记(一)_卷心菜不卷Iris的博客-CSDN博客 JVM 是运行在操作系统之上的,它与硬件没有直接的交互 JVM内存结构:   方法区:存储已被虚拟机加载的类元数据信息(元空间) 堆:存放对象实例,几乎所有的对象实例都在这里分配内存 虚拟机栈:虚拟机栈描述的是

    2024年02月12日
    浏览(5)
  • 3.Java面试题—JVM基础、内存管理、垃圾回收、JVM 调优

    3.Java面试题—JVM基础、内存管理、垃圾回收、JVM 调优

    一篇文章掌握整个JVM,JVM超详细解析!!! JVM (Java虚拟机) 是运行 Java 字节码 的 虚拟机 。 JVM 针对 不同系统 有 特定实现 ( Windows 、 Linux 等),目的是 同样的代码 在 不同平台 能运行出 相同的结果 。 Java 语言 要经过 编译 和 解释 两个步骤: 编译 :通过 编译器 将 代码 一

    2024年02月15日
    浏览(7)
  • JAVA后端开发面试基础知识(一)——JVM

    Class loader(类装载) 根据给定的全限定名类名(如: java.lang.Object)来装载class文件到 Runtime data area中的method area。 Execution engine(执行引擎) 执行classes中的指令。 Native Interface(本地接口) 与native libraries交互,是其它编程语言交互的接口。 Runtime data area(运行时数据区域) 这就是我们常说

    2024年03月10日
    浏览(8)
  • Java后端开发面试题——JVM虚拟机篇

    Java后端开发面试题——JVM虚拟机篇

    目录 什么是程序计数器? 你能给我详细的介绍Java堆吗? 什么是虚拟机栈 1. 垃圾回收是否涉及栈内存? 2. 栈内存分配越大越好吗? 3. 方法内的局部变量是否线程安全? 4.什么情况下会导致栈内存溢出? 5.堆栈的区别是什么? 能不能解释一下方法区(元空间)? 常量池 运行

    2024年02月09日
    浏览(5)
  • 【JVM】JVM五大内存区域介绍

    【JVM】JVM五大内存区域介绍

    目录  一、程序计数器(线程私有) 二、java虚拟机栈(线程私有) 2.1、虚拟机栈 2.2、栈相关测试 2.2.1、栈溢出 三、本地方法栈(线程私有) 四、java堆(线程共享) 五、方法区(线程共享) 六、实例演示         Java虚拟机在执行Java程序的过程中会把它所管理的内存划

    2024年02月15日
    浏览(9)
  • 【高频面试题】JVM篇

    【高频面试题】JVM篇

    JVM是什么: JVM(Java虚拟机)是Java程序的 运行环境 ,它是Java平台的核心组成部分之一。JVM提供了一个 运行Java字节码的虚拟机 ,负责将 Java程序解释和执行。 Java程序员可以在JVM上编写和运行Java程序,而 不用考虑底层操作系统的差异性 。JVM的特性使得Java具备了 跨平台性

    2024年02月13日
    浏览(7)
  • 12、JVM高频面试题

    12、JVM高频面试题

    JVM主要分为下面几部分 类加载器:负责将字节码文件加载到内存中 运行时数据区:用于保存java程序运行过程中需要用到的数据和相关信息 执行引擎:字节码文件并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎将字节码翻译成底层系统指令 本地库

    2024年02月03日
    浏览(6)
  • jvm的内存划分区域

    jvm的内存划分区域

    java虚拟机栈、本地方法栈、堆、程序计数器、方法区。     1.本地方法栈:用于管理本地方法的调用,里面并没有我们写的代码逻辑,其由native修饰,由 C 语言实现。 2.程序计数器:它是一块很小的内存空间,主要用来记录各个线程执行的字节码的地址,例如,分支、循环、

    2024年02月11日
    浏览(8)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包