1. 什么是JVM
- JVM指的是Java虚拟机,本质上是一个运行在计算机上的程序,他的职责是运行Java字节码文件,作用是为了支持跨平台特性
- JVM的功能有三项:第一是解释执行字节码指令;第二是管理内存中对象的分配,完成自动的垃圾回收;第三是优化热点代码提升执行效率
- JVM组成分为类加载子系统、运行时数据区、执行引擎、本地方接口这四部分
- 常用的JVM是Oracle提供的Hotspot虚拟机,也可以选择GraalVM、龙井、OpenJ9等虚拟机
2. 字节码的组成
字节码由基本信息、常量池、字段、方法、属性组成
3. 说一下运行时数据区
运行时数据区指的是JVM所管理的内存区域,其中分为两大类
线程共享-方法区、堆
方法区:存放每一个加载的类的元信息、运行时常量池、字符串常量池
堆:存放创建出来的对象
线程不共享-本地方法栈、虚拟机栈、程序计数器
本地方法栈和虚拟机栈都存放了线程中执行方法时需要使用的基础数据。程序计数器存放了当前线程执行的字节码指令在内存中的地址
直接内存主要是NIO使用,由操作系统直接管理,不属于JVM内存
4. 哪些区域会出现内存溢出,会有什么现象
内存溢出指的是内存中某一块区域的使用量超过了允许使用的最大值,从而使用内存时因空间不足而失败,虚拟机一般会抛出指定的错误。
堆:溢出之后会抛出OutOfMemoryError,并提示是Java heap Space导致的。
栈:溢出之后会抛出StackOverflowError。
方法区:溢出之后会抛出OutOfMemoryError,JDK7及之前提示永久代,JDK8及之后提示元空间。
直接内存:溢出之后会抛出OutOfMemoryError。
5. JVM在JDK6-8之间在内存区域上有什么不同
方法区的实现
● JDK7及之前的版本将方法区存放在堆区域中的永久代空间,堆的大小由虚拟机参数来控制。
● JDK8及之后的版本将方法区存放在元空间中,元空间位于操作系统维护的直接内存中,默认情况下只要不超过操作系统承受的上限,可以一直分配。也可以手动设置最大大小。
使用元空间替换永久代的原因:
1、提高内存上限:元空间使用的是操作系统内存,而不是JVM内存。如果不设置上限,只要不超过操作系统内存上限,就可以持续分配。而永久代在堆中,可使用的内存上限是有限的。所以使用元空间可以有效减少OOM情况的出现。
2、优化垃圾回收的策略:永久代在堆上,垃圾回收机制一般使用老年代的垃圾回收方式,服务器托管不够灵活。使用元空间之后单独设计了一套适合方法区的垃圾回收机制。
字符串常量池的位置
字符串常量池从方法区移动到堆的原因:
1、垃圾回收优化:字符串常量池的回收逻辑和对象的回收逻辑类似,内存不足的情况下,如果字符串常量池中的常量不被使用就可以被回收;方法区中的类的元信息回收逻辑更复杂一些。移动到堆之后,就可以利用对象的垃圾回收器,对字符串常量池进行回收。
2、让方法区大小更可控:一般在项目中,类的元信息不会占用特别大的空间,所以会给方法区设置一个比较小的上限。如果字符串常量池在方法区中,会让方法区的空间大小变得不可控。
3、intern方法的优化:JDK6版本中intern () 方法服务器托管会把第一次遇到的字符串实例复制到永久代的字符串常量池中。JDK7及之后版本中由于字符串常量池在堆上,就可以进行优化:字符串保存在堆上,把字符串的引用放入字符串常量池,减少了复制的操作。
6. 类的生命周期
- 加载:根据类的全限定名把字节码文件的内容加载并转换成合适的数据放入内存中,存放在方法区和堆上
- 连接-验证:魔数、版本号等验证,一般不需要程序员关注
- 连接-准备:为静态变量分配内存并设置初值
- 连接-解析:将常量池中的符号引用(编号)替换为直接引用(内存地址)
- 初始化:执行静态代码块和静态变量的赋值
7. 类加载器
- 启动类加载器:加载核心类
- 扩展类加载器:加载扩展类
- 应用程序类加载器:加载应用calsspath的类
- 自定义类加载器,重写findClass方法
JDK9及之后扩展类加载类变成了平台类加载器
8. 什么是双亲委派机制
当一个类加载器接收到加载类的任务时,会向上交给父类加载器查找是否加载过,再由顶向下进行加载。
双亲委派机制的作用:保证类加载的安全性,避免重复加载
9. 如何打破双亲委派机制
实现自定义类加载器、重写defineClass方法、将双亲委派机制的代码去除
10. 如何判断堆上的对象没有被引用
引用计数法会为每个对象维护一个引用计数器,当对象被引用时加1,取消引用时减1,存在循环引用问题所以Java没有使用这种方法
Java使用的是可达性分析算法来判断对象是否可以被回收。可达性分析将对象分为两类:垃圾回收的根对象(GC Root)和普通对象。
可达性分析算法指的是如果从某个到GC Root对象是可达的,对象就不可被回收。最常见的是GC Root对象会引用栈上的局部变量和静态变量导致对象不可回收
哪些对象被称之为GC Root对象呢?
● 线程Thread对象,引用线程栈帧中的方法参数、局部变量等。
● 系统类加载器加载的java.lang.Class对象,引用类的静态变量。
● 监视器对象,用来保存同步锁synchronized关键字持有的对象。
● 本地方法调用时使用的全局对象。
JVM中都有哪些引用类型
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: 源码视角,vue3为什么推荐用ref,而不是reactive
ref和reactive是 Vue3 中实现响应式数据的核心 API。ref用于包装基本数据类型,而 reactive 用于处理对象和数组。尽管reactive似乎更适合处理对象,但Vue3 官方文档更推荐使用ref。 我的想法,ref就是比reactive好…