Java面试问题整理笔记-JVM基础知识

news/2024/7/5 3:00:26

JVM

  • 1.内存区域
    • 1.1程序计数器(线程私有)
    • 1.2虚拟机栈(线程私有)
    • 1.3本地方法区(线程私有)
    • 1.4堆(Heap-线程共享) -运行时数据区
      • 1.4.1 逃逸机制
    • 1.5方法区/永久代(线程共享)
  • 2.类加载
    • 2.1加载
    • 2.2验证
    • 2.3准备
    • 2.4解析
    • 2.5初始化
    • 2.6类加载机制-双亲委派机制
    • 2.7类加载器
      • 2.7.1启动类加载器(Bootstrap ClassLoader)
      • 2.7.2扩展类加载器(Extension ClassLoader)
      • 2.7.3应用程序类加载器(Application ClassLoader)
  • 3.垃圾回收
    • 3.1如何判断对象可以被回收?
      • 3.1.1引用计数
      • 3.1.2可达性分析(Reachability Analysis)
    • 3.2垃圾收集算法
      • 3.2.1标记 -清除算法
      • 3.2.2复制算法
      • 3.2.3标记-压缩算法
      • 3.2.4分代收集算法
    • 3.3Minor GC与Full GC分别在什么时候发生?
    • 4.你知道哪些JVM性能调优
      • 4.1设定堆内存大小
    • 4.2设定新生代大小
    • 4.3设定垃圾回收器
  • 5.JAVA 四中引用类型
    • 5.1强引用
    • 5.2软引用
    • 5.3弱引用
    • 5.4虚引用

1.内存区域

请添加图片描述

1.1程序计数器(线程私有)

  • 一块较小的内存空间, 是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程私有” 的内存。
  • 正在执行 java 方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址) 。如果还是 Native 方法,则为空。
  • 这个内存区域是唯一一个在虚拟机中没有规定任何 OutOfMemoryError 情况的区域

1.2虚拟机栈(线程私有)

是描述java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储

  • 局部变量表
  • 操作数栈
  • 动态链接
  • 方法出口

等信息。 每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

栈帧( Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)、 方法返回值和异常分派( Dispatch Exception)。 栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。

1.3本地方法区(线程私有)

本地方法区和 Java Stack 作用类似, 区别是虚拟机栈为执行 Java 方法服务, 而本地方法栈则为Native 方法服务, 如果一个 VM 实现使用 C-linkage 模型来支持 Native 调用, 那么该栈将会是一个C 栈,但 HotSpot VM 直接就把本地方法栈和虚拟机栈合二为一。

1.4堆(Heap-线程共享) -运行时数据区

是被线程共享的一块内存区域, 创建的对象和数组都保存在 Java 堆内存中,也是垃圾收集器进行垃圾收集的最重要的内存区域。 由于现代 VM 采用分代收集算法, 因此 Java 堆从 GC 的角度还可以细分为:

  • 新生代(Eden 区、 From Survivor 区和 To Survivor 区)
  • 老年代

1.4.1 逃逸机制

Java 世界中“几乎”所有的对象都在堆中分配,但是,随着JIT 编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“对”了。从 JDK 1.7 开始已经默认开启逃逸分析,如果某些方法中的对象引用没有被返回或者未被外面使用(也就是未逃逸出去),那么对象可以直接在栈上分配内存

1.5方法区/永久代(线程共享)

即我们常说的永久代(Permanent Generation), 用于存储被 JVM 加载的

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

HotSpot VM把GC分代收集扩展至方法区, 即使用Java堆的永久代来实现方法区, 这样 HotSpot 的垃圾收集器就可以像管理 Java 堆一样管理这部分内存,而不必为方法区开发专门的内存管理器(永久带的内存回收的主要目标是针对常量池的回收和类型的卸载, 因此收益一般很小)

2.类加载

请添加图片描述

2.1加载

加载是类加载过程中的一个阶段, 这个阶段会在内存中生成一个代表这个类的 java.lang.Class 对象, 作为方法区这个类的各种数据的入口。注意这里不一定非得要从一个 Class 文件获取,这里既可以从 ZIP 包中读取(比如从 jar 包和 war 包中读取),也可以在运行时计算生成(动态代理),也可以由其它文件生成(比如将 JSP 文件转换成对应的 Class 类)。

2.2验证

这一阶段的主要目的是为了确保 Class 文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

2.3准备

准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间。注意这里所说的初始值概念,比如一个类变量定义为:

public static int v = 8080;

实际上变量 v 在准备阶段过后的初始值为 0 而不是 8080将 v 赋值为 8080的 put static 指令是程序被编译后, 存放于类构造器<client>方法之中。但是注意如果声明为:

public static final int v = 8080;

编译阶段会为 v 生成 ConstantValue 属性,在准备阶段虚拟机会根据 ConstantValue 属性将 v赋值为8080。

2.4解析

解析阶段是指虚拟机将常量池中符号引用替换为直接引用的过程。符号引用就是 class 文件中的:

  • CONSTANT_Class_info
  • CONSTANT_Field_info
  • CONSTANT_Method_info

等类型的常量。

2.5初始化

初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载器以外,其它操作都由 JVM 主导。到了初始阶段,才开始真正执行类中定义的 Java 程序代码。

2.6类加载机制-双亲委派机制

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class), 子类加载器才会尝试自己去加载。
采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object 对象

2.7类加载器

请添加图片描述

虚拟机设计团队把加载动作放到 JVM 外部实现,以便让应用程序决定如何获取所需的类, JVM 提供了 3 种类加载器:

2.7.1启动类加载器(Bootstrap ClassLoader)

负责加载 JAVA_HOME\lib 目录中的, 或通过-Xbootclasspath 参数指定路径中的, 且被虚拟机认可(按文件名识别, 如 rt.jar) 的类。

2.7.2扩展类加载器(Extension ClassLoader)

负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类库。

2.7.3应用程序类加载器(Application ClassLoader)

负责加载用户路径(classpath)上的类库。JVM 通过双亲委派模型进行类的加载, 当然我们也可以通过继承 java.lang.ClassLoader实现自定义的类加载器。

3.垃圾回收

3.1如何判断对象可以被回收?

3.1.1引用计数

每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。

此方法简单,无法解决对象相互循环引用的问题

3.1.2可达性分析(Reachability Analysis)

从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,不可达对象。 要注意的是,不可达对象不等价于可回收对象, 不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。

3.2垃圾收集算法

GC最基础的算法有三种: 标记 -清除算法、复制算法、标记-压缩算法,我们常用的垃圾回收器一般都采用分代收集算法。

3.2.1标记 -清除算法

请添加图片描述

“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。从图中我们就可以发现,该算法最大的问题是内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题

3.2.2复制算法

请添加图片描述

“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这种算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半。且存活对象增多的话, Copying 算法的效率会大大降低。

3.2.3标记-压缩算法

请添加图片描述

标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

3.2.4分代收集算法

“分代收集”(Generational Collection)算法,把Java堆分为新生代和老年代,老生代(老年代与标记复制算法 )的特点是每次垃圾回收时只有少量对象需要被回收,新生代(新生代与复制算法 )的特点是每次垃圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法。

3.3Minor GC与Full GC分别在什么时候发生?

  • 新生代内存不够用时候发生MGC也叫YGC

  • JVM内存不够的时候发生FGC

4.你知道哪些JVM性能调优

4.1设定堆内存大小

-Xmx:堆内存最大限制。

4.2设定新生代大小

新生代不宜太小,否则会有大量对象涌入老年代

  • -XX:NewSize:新生代大小
  • -XX:NewRatio 新生代和老生代占比
  • -XX:SurvivorRatio:伊甸园空间和幸存者空间的占比

4.3设定垃圾回收器

  • 年轻代用 -XX:+UseParNewGC
  • 年老代用-XX:+UseConcMarkSweepGC

5.JAVA 四中引用类型

5.1强引用

在 Java 中最常见的就是强引用, 把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到 JVM 也不会回收。因此强引用是造成 Java 内存泄漏的主要原因之一。

5.2软引用

软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。

可用场景: 创建缓存的时候,创建的对象放进缓存中,当内存不足时,JVM就会回收早先创建的对象。

5.3弱引用

弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。

可用场景: Java源码中的 java.util.WeakHashMap 中的 key 就是使用弱引用,我的理解就是,一旦我不需要某个引用,JVM会自动帮我处理它,这样我就不需要做其它操作。

5.4虚引用

虚引用需要 PhantomReference 类来实现,它不能单独使用,必须和引用队列联合使用。 虚引用的主要作用是跟踪对象被垃圾回收的状态。

可用场景: 对象销毁前的一些操作,比如说资源释放等。** Object.finalize() 虽然也可以做这类动作,但是这个方式即不安全又低效



http://lihuaxi.xjx100.cn/news/51970.html

相关文章

DID系列3--DID 生态系统

资料来源&#xff1a;极易被忽视的DID&#xff0c;是通往Web3的护照 - 碳链价值来自W3C的DID规范是被广泛接受的标准&#xff0c;确保身份系统可以在不同的网络和平台上互操作。下面是DID架构的概述。DID是互联网上的一个地址&#xff0c;某人可以直接拥有和控制。它可以用来寻…

Map集合

一、概述 1、Map集合是一种双列集合&#xff0c;每个元素包含两个数据 2、Map集合的每个元素格式&#xff1a;Key value 3、Map集合也被称为键值对集合 Map集合是键值对集合 Map集合非常适合做购物车这种业务场景 适应最对的Map集合时HashMap 二、Map集合体系的特点 1…

qsort函数模拟实现(利用冒泡函数实现)

文章目录1.qsort函数介绍2.模拟实现qsort函数2.1冒泡排序2.2使用回调函数&#xff0c;模拟实现qsort&#xff08;采用冒泡的方式&#xff09;3.一道排序题3.1解析1.qsort函数介绍 下面我们来看代码 int int_cmp(const void* p1, const void* p2) {return(*(int*)p1 - *(int*)p…

【数据结构与算法01】 算法的复杂度

文章目录时间复杂度的概念时间复杂度&#xff1a;常[1]、对[logn]、幂[n^2]、 指[2^n]、阶[n!]例题❗易错提醒空间复杂度&#x1f354;算法原地工作&#xff1a;算法所需的内存空间为常量例题时间复杂度的概念 例1&#xff1a;假设n3000n3000n3000 i2998,print("I love Yo…

head first java3

QA 为啥所有东西都在类中&#xff1a;Java面向对象&#xff0c;类是对象的蓝图&#xff0c;Java绝大多数都是对象 每个类都需要加一个main吗&#xff1a;一个程序中&#xff0c;一个就够 int x2;while(x) 对吗&#xff1a;错误&#xff0c;while中间是Boolean类型。boolean xtr…

java基于springboot+Vue+nodejs的高校运动会报名管理系统 element

运动是伴随人类一生的一种行为和活动&#xff0c;只有不断的运动才能够彰显生命的意义&#xff0c;尤其是当代的学生&#xff0c;课业繁重往往忽略了体育锻炼&#xff0c;为了能够提高学子们对体育运动的积极性&#xff0c;基本所有的高校每年都会定期的举办运动会。传统的运动…

MySQL入门学习笔记(上)

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 个人主页&#xff1a;BoBooY的CSDN博客_Java领域博主 前言&#xff1a;本篇文章总结了 MySQL的入门知识点&#xff08;上&#xff09;&#xff0c;希望通过 文字介绍 代码 图片的形式帮助大家快速掌握 MySQL入门知识点&…

什么是压缩算法及压缩算法定义

目录 一、什么是压缩算法 文件存储 二、压缩算法定义 一、什么是压缩算法 我想必都有过 压缩 和 解压缩 文件的经历&#xff0c;当文件太大时&#xff0c;我会使用文件压缩来降低文件的占用空间&#xff0c;比如微信上传文件的限制是100 MB&#xff0c;我这有个文件无法上传…