1.什么是JVM?

JVM——Java虚拟机,它是Java实现平台⽆关性的基⽯。
Java程序运⾏的时候,编译器将Java⽂件编译成平台⽆关的Java字节码⽂件(.class),接下来对
应平台JVM对字节码⽂件进⾏解释,翻译成对应平台匹配的机器指令并运⾏。
同时JVM也是⼀个跨语⾔的平台,和语⾔⽆关,只和class的⽂件格式关联,任何语⾔,只要
能翻译成符合规范的字节码⽂件,都能被JVM运⾏。
JVM内存分为线程私有区和线程共享区,其中 ⽅法区 和 堆 是线程共享区, 虚拟机栈 、 本地
⽅法栈 和 程序计数器 是线程隔离的数据区。
1、程序计数器
程序计数器(Program Counter Register)也被称为PC寄存器,是⼀块较⼩的内存空间。
它可以看作是当前线程所执⾏的字节码的⾏号指⽰器。
2Java虚拟机栈
Java虚拟机栈(Java Virtual Machine Stack)也是线程私有的,它的⽣命周期与线程相同。
Java虚拟机栈描述的是Java⽅法执⾏的线程内存模型:⽅法执⾏时,JVM会同步创建⼀个栈
帧,⽤来存储局部变量表、操作数栈、动态连接等。

3、本地⽅法栈
本地⽅法栈(Native Method Stacks)与虚拟机栈所发挥的作⽤是⾮常相似的,其区别只是虚
拟机栈为虚拟机执⾏Java⽅法(也就是字节码)服务,⽽本地⽅法栈则是为虚拟机使⽤到的本
地(Native)⽅法服务。
Java 虚拟机规范允许本地⽅法栈被实现成固定⼤⼩的或者是根据计算动态扩展和收缩的。
4Java
对于Java应⽤程序来说,Java堆(Java Heap)是虚拟机所管理的内存中最⼤的⼀块。Java堆是
被所有线程共享的⼀块内存区域,在虚拟机启动时创建。此内存区域的唯⼀⽬的就是存放对
象实例,Java⾥“⼏乎”所有的对象实例都在这⾥分配内存。
Java堆是垃圾收集器管理的内存区域,因此⼀些资料中它也被称作“GC堆”(Garbage Collected
Heap,)。从回收内存的⾓度看,由于现代垃圾收集器⼤部分都是基于分代收集理论设计
的,所以Java堆中经常会出现 新⽣代 、 ⽼年代 、 Eden空间 、 From Survivor空间 、 To
Survivor空间 等名词,需要注意的是这种划分只是根据垃圾回收机制来进⾏的划分,不是
Java虚拟机规范本⾝制定的。

5.⽅法区
⽅法区是⽐较特别的⼀块区域,和堆类似,它也是各个线程共享的内存区域,⽤于存储已被
虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
它特别在Java虚拟机规范对它的约束⾮常宽松,所以⽅法区的具体实现历经了许多变迁,例如
jdk1.7之前使⽤永久代作为⽅法区的实现。

4.为什么使⽤元空间替代永久代作为⽅法区的实现?
Java虚拟机规范规定的⽅法区只是换种⽅式实现。有客观和主观两个原因。
客观上使⽤永久代来实现⽅法区的决定的设计导致了Java应⽤更容易遇到内存溢出的问题
(永久代有-XX:MaxPermSize的上限,即使不设置也有默认⼤⼩,⽽J9和JRockit只要没
有触碰到进程可⽤内存的上限,例如32位系统中的4GB限制,就不会出问题),⽽且有极
少数⽅法 (例如String::intern())会因永久代的原因⽽导致不同虚拟机下有不同的表现。
主观上当Oracle收购BEA获得了JRockit的所有权后,准备把JRockit中的优秀功能,譬如
Java Mission Control管理⼯具,移植到HotSpot 虚拟机时,但因为两者对⽅法区实现的差异
⽽⾯临诸多困难。考虑到HotSpot未来的发展,在JDK 6的 时候HotSpot开发团队就有放弃
永久代,逐步改为采⽤本地内存(Native Memory)来实现⽅法区的计划了,到了JDK 7的
HotSpot,已经把原本放在永久代的字符串常量池、静态变量等移出,⽽到了 JDK 8,终于
完全废弃了永久代的概念,改⽤与JRockit、J9⼀样在本地内存中实现的元空间(Meta-
206
space)来代替,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。
5.对象创建的过程了解吗?
在JVM中对象的创建,我们从⼀个new指令开始:
⾸先检查这个指令的参数是否能在常量池中定位到⼀个类的符号引⽤
检查这个符号引⽤代表的类是否已被加载、解析和初始化过。如果没有,就先执⾏相应的
类加载过程
类加载检查通过后,接下来虚拟机将为新⽣对象分配内存。
内存分配完成之后,虚拟机将分配到的内存空间(但不包括对象头)都初始化为零值。
接下来设置对象头,请求头⾥包含了对象是哪个类的实例、如何才能找到类的元数据信
息、对象的哈希码、对象的GC分代年龄等信息。

6.什么是指针碰撞?什么是空闲列表?
内存分配有两种⽅式,指针碰撞(Bump The Pointer)、空闲列表(Free List)。
指针碰撞:假设Java堆中内存是绝对规整的,所有被使⽤过的内存都被放在⼀边,空闲的
内存被放在另⼀边,中间放着⼀个指针作为分界点的指⽰器,那所分配内存就仅仅是把那
个指针向空闲空间⽅向挪动⼀段与对象⼤⼩相等的距离,这种分配⽅式称为“指针碰撞”。
空闲列表:如果Java堆中的内存并不是规整的,已被使⽤的内存和空闲的内存相互交错在
⼀起,那就没有办法简单地进⾏指针碰撞了,虚拟机就必须维护⼀个列表,记录上哪些内
存块是可⽤的,在分配的时候从列表中找到⼀块⾜够⼤的空间划分给对象实例,并更新列
表上的记录,这种分配⽅式称为“空闲列表”。
两种⽅式的选择由Java堆是否规整决定,Java堆是否规整是由选择的垃圾收集器是否具有
压缩整理能⼒决定的。

14.Java中可作为GC Roots的对象有哪⼏种?
可以作为GC Roots的主要有四种对象:
虚拟机栈(栈帧中的本地变量表)中引⽤的对象
⽅法区中类静态属性引⽤的对象
⽅法区中常量引⽤的对象
本地⽅法栈中JNI引⽤的对象
15.说⼀下对象有哪⼏种引⽤?
Java中的引⽤有四种,分为强引⽤(Strongly Reference)、软引⽤(Soft Reference)、弱引⽤
(Weak Reference)和虚引⽤(Phantom Reference)4种,这4种引⽤强度依次逐渐减弱。

16.finalize()⽅法了解吗?有什么作⽤?
⽤⼀个不太贴切的⽐喻,垃圾回收就是古代的秋后问斩,finalize()就是⼑下留⼈,在⼈犯被处
决之前,还要做最后⼀次审计,青天⼤⽼爷看看有没有什么冤情,需不需要⼑下留⼈。
如果对象在进⾏可达性分析后发现没有与GC Roots相连接的引⽤链,那它将会被第⼀次标
记,随后进⾏⼀次筛选,筛选的条件是此对象是否有必要执⾏finalize()⽅法。如果对象在在
finalize()中成功拯救⾃⼰——只要重新与引⽤链上的任何⼀个对象建⽴关联即可,譬如把⾃⼰
(this关键字)赋值给某个类变量或者对象的成员变量,那在第⼆次标记时它就”逃过⼀劫“;
但是如果没有抓住这个机会,那么对象就真的要被回收了。
17.Java堆的内存分区了解吗?
按照垃圾收集,将Java堆划分为新⽣代 (Young Generation)和⽼年代(Old Generation
两个区域,新⽣代存放存活时间短的对象,⽽每次回收后存活的少量对象,将会逐步晋升到
⽼年代中存放。
⽽新⽣代又可以分为三个区域,eden、from、to,⽐例是8:1:1,⽽新⽣代的内存分区同样
是从垃圾收集的⾓度来分配的。

18.垃圾收集算法了解吗?
垃圾收集算法主要有三种:
1. 标记-清除算法
见名知义, 标记-清除 (Mark-Sweep)算法分为两个阶段:
标记 : 标记出所有需要回收的对象
清除 :回收所有被标记的对象
标记-清除算法⽐较基础,但是主要存在两个缺点:
执⾏效率不稳定,如果Java堆中包含⼤量对象,⽽且其中⼤部分是需要被回收的,这时必
须进⾏⼤量标记和清除的动作,导致标记和清除两个过程的执⾏效率都随对象数量增长⽽
降低。
内存空间的碎⽚化问题,标记、清除之后会产⽣⼤量不连续的内存碎⽚,空间碎⽚太多可
能会导致当以后在程序运⾏过程中需要分配较⼤对象时⽆法找到⾜够的连续内存⽽不得不
提前触发另⼀次垃圾收集动作。
2. 标记-复制算法
标记-复制算法解决了标记-清除算法⾯对⼤量可回收对象时执⾏效率低的问题。
过程也⽐较简单:将可⽤内存按容量划分为⼤⼩相等的两块,每次只使⽤其中的⼀块。当这
⼀块的内存⽤完了,就将还存活着的对象复制到另外⼀块上⾯,然后再把已使⽤过的内存空
间⼀次清理掉。
这种算法存在⼀个明显的缺点:⼀部分空间没有使⽤,存在空间的浪费。
新⽣代垃圾收集主要采⽤这种算法,因为新⽣代的存活对象⽐较少,每次复制的只是少量的
存活对象。当然,实际新⽣代的收集不是按照这个⽐例。
3. 标记-整理算法
为了降低内存的消耗,引⼊⼀种针对性的算法: 标记-整理 (Mark-Compact)算法。
其中的标记过程仍然与“标记-清除”算法⼀样,但后续步骤不是直接对可回收对象进⾏清理,
⽽是让所有存活的对象都向内存空间⼀端移动,然后直接清理掉边界以外的内存。
标记-整理算法主要⽤于⽼年代,移动存活对象是个极为负重的操作,⽽且这种操作需要Stop
The World才能进⾏,只是从整体的吞吐量来考量,⽼年代使⽤标记-整理算法更加合适。
19.说⼀下新⽣代的区域划分?
新⽣代的垃圾收集主要采⽤标记-复制算法,因为新⽣代的存活对象⽐较少,每次复制少量的
存活对象效率⽐较⾼。
基于这种算法,虚拟机将内存分为⼀块较⼤的Eden空间和两块较⼩的 Survivor空间,每次分配
内存只使⽤Eden和其中⼀块Survivor。发⽣垃圾收集时,将Eden和Survivor中仍然存活的对象
⼀次性复制到另外⼀块Survivor空间上,然后直接清理掉Eden和已⽤过的那块Survivor空间。
默认Eden和Survivor的⼤⼩⽐例是8∶1。

Young GC之前检查⽼年代 :在要进⾏ Young GC 的时候,发现 ⽼年代可⽤的连续内存空
间 < 新⽣代历次Young GC后升⼊⽼年代的对象总和的平均⼤⼩ ,说明本次Young GC后可
能升⼊⽼年代的对象⼤⼩,可能超过了⽼年代当前可⽤内存空间,那就会触发 Full GC。
Young GC之后⽼年代空间不⾜ :执⾏Young GC之后有⼀批对象需要放⼊⽼年代,此时⽼
年代就是没有⾜够的内存空间存放这些对象了,此时必须⽴即触发⼀次Full GC
⽼年代空间不⾜ ,⽼年代内存使⽤率过⾼,达到⼀定⽐例,也会触发Full GC。
空间分配担保失败 ( Promotion Failure),新⽣代的 To 区放不下从 Eden 和 From 拷贝过
来对象,或者新⽣代对象 GC 年龄到达阈值需要晋升这两种情况,⽼年代如果放不下的话
都会触发 Full GC。
⽅法区内存空间不⾜ :如果⽅法区由永久代实现,永久代空间不⾜ Full GC。
System.gc()等命令触发 :System.gc()、jmap -dump 等命令会触发 full gc

长期存活的对象将进⼊⽼年代

在对象的对象头信息中存储着对象的迭代年龄,迭代年龄会在每次YoungGC之后对象的移区操
作中增加,每⼀次移区年龄加⼀.当这个年龄达到15(默认)之后,这个对象将会被移⼊⽼年代。
可以通过这个参数设置这个年龄值。
- XX:MaxTenuringThreshold
⼤对象直接进⼊⽼年代
有⼀些占⽤⼤量连续内存空间的对象在被加载就会直接进⼊⽼年代.这样的⼤对象⼀般是⼀些
数组,长字符串之类的对。
HotSpot虚拟机提供了这个参数来设置。
-XX:PretenureSizeThreshold
动态对象年龄判定
为了能更好地适应不同程序的内存状况,HotSpot虚拟机并不是永远要求对象的年龄必须达到-
XX:MaxTenuringThreshold才能晋升⽼年代,如果在Survivor空间中相同年龄所有对象⼤⼩的
总和⼤于Survivor空间的⼀半,年龄⼤于或等于该年龄的对象就可以直接进⼊⽼年代。
空间分配担保
假如在Young GC之后,新⽣代仍然有⼤量对象存活,就需要⽼年代进⾏分配担保,把Survivor
⽆法容纳的对象直接送⼊⽼年代。

CMS收集器
CMS(Concurrent Mark Sweep)收集器是⼀种以获取最短回收停顿时间为⽬标的收集器,同
样是⽼年代的收集器,采⽤标记-清除算法。
Garbage First收集器
Garbage First(简称G1)收集器是垃圾收集器的⼀个颠覆性的产物,它开创了局部收集的设计
思路和基于Region的内存布局形式。

27.G1垃圾收集器了解吗?
Garbage First(简称G1)收集器是垃圾收集器的⼀个颠覆性的产物,它开创了局部收集的设计
思路和基于Region的内存布局形式。
虽然G1也仍是遵循分代收集理论设计的,但其堆内存的布局与其他收集器有⾮常明显的差
异。以前的收集器分代是划分新⽣代、⽼年代、持久代等。
G1把连续的Java堆划分为多个⼤⼩相等的独⽴区域(Region),每⼀个Region都可以根据需
要,扮演新⽣代的Eden空间、Survivor空间,或者⽼年代空间。收集器能够对扮演不同⾓⾊的
Region采⽤不同的策略去处理。
这样就避免了收集整个堆,⽽是按照若⼲个Region集进⾏收集,同时维护⼀个优先级列表,
跟踪各个Region回收的“价值,优先收集价值⾼的Region。
G1收集器的运⾏过程⼤致可划分为以下四个步骤:
初始标记 (initial mark),标记了从GC Root开始直接关联可达的对象。STW(Stop the
World)执⾏。
并发标记 (concurrent marking),和⽤户线程并发执⾏,从GC Root开始对堆中对象进⾏
可达性分析,递归扫描整个堆⾥的对象图,找出要回收的对象、
最终标记 (Remark),STW,标记再并发标记过程中产⽣的垃圾。
筛选回收 (Live Data Counting And Evacuation),制定回收计划,选择多个Region 构成
回收集,把回收集中Region的存活对象复制到空的Region中,再清理掉整个旧 Region的全
部空间。需要STW。

28.有了CMS,为什么还要引⼊G1
优点:CMS最主要的优点在名字上已经体现出来——并发收集、低停顿。
缺点:CMS同样有三个明显的缺点。
Mark Sweep算法会导致内存碎⽚⽐较多
CMS的并发能⼒⽐较依赖于CPU资源,并发回收时垃圾收集线程可能会抢占⽤户线程的资
源,导致⽤户程序性能下降。
并发清除阶段,⽤户线程依然在运⾏,会产⽣所谓的理“浮动垃圾”(Floating Garbage),
本次垃圾收集⽆法处理浮动垃圾,必须到下⼀次垃圾收集才能处理。如果浮动垃圾太多,
会触发新的垃圾回收,导致性能降低。
G1主要解决了内存碎⽚过多的问题。
29.你们线上⽤的什么垃圾收集器?为什么要⽤它?
采⽤ Parallel New + CMS 的组合,我们⽐较关注服务的响应速度,所以采⽤了CMS来降低
停顿时间。
或者⼀步到位:
我们线上采⽤了设计⽐较优秀的G1垃圾收集器,因为它不仅满⾜我们低停顿的要求,⽽且解
决了CMS的浮动垃圾问题、内存碎⽚问题。
30.垃圾收集器应该如何选择?
垃圾收集器的选择需要权衡的点还是⽐较多的——例如运⾏应⽤的基础设施如何?使⽤JDK的
发⾏商是什么?等等……
这⾥简单地列⼀下上⾯提到的⼀些收集器的适⽤场景:
Serial :如果应⽤程序有⼀个很⼩的内存空间(⼤约100 MB)亦或它在没有停顿时间要求
的单线程处理器上运⾏。
Parallel:如果优先考虑应⽤程序的峰值性能,并且没有时间要求要求,或者可以接受1秒
或更长的停顿时间。
CMS/G1:如果响应时间⽐吞吐量优先级⾼,或者垃圾收集暂停必须保持在⼤约1秒以
内。
ZGC:如果响应时间是⾼优先级的,或者堆空间⽐较⼤。
31.对象⼀定分配在堆中吗?有没有了解逃逸分析技术?
对象⼀定分配在堆中吗? 不⼀定的。
随着JIT编译期的发展与逃逸分析技术逐渐成熟,所有的对象都分配到堆上也渐渐变得不那么
“绝对”了。其实,在编译期间,JIT会对代码做很多优化。其中有⼀部分优化的⽬的就是减少
内存堆分配压⼒,其中⼀种重要的技术叫做逃逸分析。
什么是逃逸分析?
逃逸分析是指分析指针动态范围的⽅法,它同编译器优化原理的指针分析和外形分析相关
联。当变量(或者对象)在⽅法中分配后,其指针有可能被返回或者被全局引⽤,这样就会
被其他⽅法或者线程所引⽤,这种现象称作指针(或者引⽤)的逃逸(Escape)。
通俗点讲,当⼀个对象被new出来之后,它可能被外部所调⽤,如果是作为参数传递到外部
了,就称之为⽅法逃逸
逃逸分析的好处
栈上分配
如果确定⼀个对象不会逃逸到线程之外,那么久可以考虑将这个对象在栈上分配,对象占⽤
的内存随着栈帧出栈⽽销毁,这样⼀来,垃圾收集的压⼒就降低很多。
同步消除
线程同步本⾝是⼀个相对耗时的过程,如果逃逸分析能够确定⼀个变量不会逃逸出线程,⽆
法被其他线程访问,那么这个变量的读写肯定就不会有竞争, 对这个变量实施的同步措施也
就可以安全地消除掉。
标量替换
如果⼀个数据是基本数据类型,不可拆分,它就被称之为标量。把⼀个Java对象拆散,将其⽤
到的成员变量恢复为原始类型来访问,这个过程就称为标量替换。假如逃逸分析能够证明⼀
个对象不会被⽅法外部访问,并且这个对象可以被拆散,那么可以不创建对象,直接⽤创建
若⼲个成员变量代替,可以让对象的成员变量在栈上分配和读写。
32.有哪些常⽤的命令⾏性能监控和故障处理⼯具?
操作系统⼯具
top:显⽰系统整体资源使⽤情况
vmstat:监控内存和CPU
iostat:监控IO使⽤
netstat:监控⽹络使⽤
JDK性能监控⼯具
jps:虚拟机进程查看
jstat:虚拟机运⾏时信息查看
jinfo:虚拟机配置查看
jmap:内存映像(导出)
jhat:堆转储快照分析
jstack:Java堆栈跟踪
jcmd:实现上⾯除了jstat外所有命令的功能
除此之外,还有⼀些第三⽅的⼯具:
MAT
Java 堆内存分析⼯具。
GChisto
GC ⽇志分析⼯具。
GCViewer
GC ⽇志分析⼯具。
JProfiler
商⽤的性能分析利器。
arthas
阿⾥开源诊断⼯具。
async-profiler
Java 应⽤性能分析⼯具,开源、⽕焰图、跨平台。
34.JVM的常见参数配置知道哪些?
⼀些常见的参数配置:
堆配置:
-Xms:初始堆⼤⼩
-Xmx:最⼤堆⼤⼩
-XX:NewSize=n:设置年轻代⼤⼩
-XX:NewRatio=n:设置年轻代和年⽼代的⽐值。如:为3表⽰年轻代和年⽼代⽐值为1:3,
年轻代占整个年轻代年⽼代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的⽐值。注意Survivor区有两个。
如3表⽰Eden: 3 Survivor:2,⼀个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代⼤⼩
收集器设置:
-XX:+UseSerialGC:设置串⾏收集器
-XX:+UseParallelGC:设置并⾏收集器
-XX:+UseParalledlOldGC:设置并⾏年⽼代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
并⾏收集器设置
-XX:ParallelGCThreads=n:设置并⾏收集器收集时使⽤的CPU数。并⾏收集线程数
-XX:MaxGCPauseMillis=n:设置并⾏收集最⼤的暂停时间(如果到这个时间了,垃圾回收
器依然没有回收完,也会停⽌回收)
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运⾏时间的百分⽐。公式为:1/(1+n)
-XX:+CMSIncrementalMode:设置为增量模式。适⽤于单CPU情况
-XX:ParallelGCThreads=n:设置并发收集器年轻代⼿机⽅式为并⾏收集时,使⽤的CPU数。
并⾏收集线程数
打印GC回收的过程⽇志信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
实际上,JVM调优是不得已⽽为之,有那功夫,好好把烂代码重构⼀下不⽐瞎调JVM强。
但是,⾯试官⾮要问怎么办?可以从处理问题的⾓度来回答(对应图中事后),这是⼀个中
规中矩的案例:电商公司的运营后台系统,偶发性的引发OOM异常,堆内存溢出。
1、因为是偶发性的,所以第⼀次简单的认为就是堆内存不⾜导致,单⽅⾯的加⼤了堆内存从
4G调整到8G -Xms8g。
2、但是问题依然没有解决,只能从堆内存信息下⼿,通过开启了-
XX:+HeapDumpOnOutOfMemoryError参数 获得堆内存的dump⽂件。
3、⽤JProfiler 对 堆dump⽂件进⾏分析,通过JProfiler查看到占⽤内存最⼤的对象是String对
象,本来想跟踪着String对象找到其引⽤的地⽅,但dump⽂件太⼤,跟踪进去的时候总是卡
死,⽽String对象占⽤⽐较多也⽐较正常,最开始也没有认定就是这⾥的问题,于是就从线程
信息⾥⾯找突破点。
4、通过线程进⾏分析,先找到了⼏个正在运⾏的业务线程,然后逐⼀跟进业务线程看了下代
码,有个⽅法引起了我的注意, 导出订单信息 。
5、因为订单信息导出这个⽅法可能会有⼏万的数据量,⾸先要从数据库⾥⾯查询出来订单信
息,然后把订单信息⽣成excel,这个过程会产⽣⼤量的String对象。
6、为了验证⾃⼰的猜想,于是准备登录后台去测试下,结果在测试的过程中发现导出订单的
按钮前端居然没有做点击后按钮置灰交互事件,后端也没有做防⽌重复提交,因为导出订单
数据本来就⾮常慢,使⽤的⼈员可能发现点击后很久后页⾯都没反应,然后就⼀直点,结果
就⼤量的请求进⼊到后台,堆内存产⽣了⼤量的订单对象和EXCEL对象,⽽且⽅法执⾏⾮常
慢,导致这⼀段时间内这些对象都⽆法被回收,所以最终导致内存溢出。
7、知道了问题就容易解决了,最终没有调整任何JVM参数,只是做了两个处理:
在前端的导出订单按钮上加上了置灰状态,等后端响应之后按钮才可以进⾏点击
后端代码加分布式锁,做防重处理
这样双管齐下,保证导出的请求不会⼀直打到服务端,问题解决!

41.有没有处理过内存溢出问题?
内存泄漏和内存溢出⼆者关系⾮常密切,内存溢出可能会有很多原因导致,内存泄漏最可能
的罪魁祸⾸之⼀。
排查过程和排查内存泄漏过程类似。
虚拟机执⾏
42.能说⼀下类的⽣命周期吗?
⼀个类从被加载到虚拟机内存中开始,到从内存中卸载,整个⽣命周期需要经过七个阶段:
加载 (Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化
(Initialization)、使⽤(Using)和卸载(Unloading),其中验证、准备、解析三个部分统称
为连接(Linking)。

1)通过⼀个类的全限定名来获取定义此类的⼆进制字节流。
2)将这个字节流所代表的静态存储结构转化为⽅法区的运⾏时数据结构。
3)在内存中⽣成⼀个代表这个类的java.lang.Class对象,作为⽅法区这个类的各种数据的
访问⼊⼜。
加载阶段结束后,Java虚拟机外部的⼆进制字节流就按照虚拟机所设定的格式存储在⽅法区之
中了,⽅法区中的数据存储格式完全由虚拟机实现⾃⾏定义,《Java虚拟机规范》未规定此区
域的具体数据结构。
类型数据妥善安置在⽅法区之后,会在Java堆内存中实例化⼀个java.lang.Class类的对象, 这
个对象将作为程序访问⽅法区中的类型数据的外部接⼜。
44.类加载器有哪些?
主要有四种类加载器:
启动类加载器 (Bootstrap ClassLoader)⽤来加载java核⼼类库,⽆法被java程序直接引⽤。
扩展类加载器 (extensions class loader):它⽤来加载 Java 的扩展库。Java 虚拟机的实现会提
供⼀个扩展库⽬录。该类加载器在此⽬录⾥⾯查找并加载 Java 类。
系统类加载器 (system class loader):它根据 Java 应⽤的类路径(CLASSPATH)来加载
Java 类。⼀般来说,Java 应⽤的类都是由它来完成加载的。可以通过
ClassLoader.getSystemClassLoader()来获取它。
⽤户⾃定义类加载器 (user class loader),⽤户通过继承 java.lang.ClassLoader类的⽅式⾃⾏
实现的类加载器。

双亲委派模型的⼯作过程:如果⼀个类加载器收到了类加载的请求,它⾸先不会⾃⼰去尝试
加载这个类,⽽是把这个请求委派给⽗类加载器去完成,每⼀个层次的类加载器都是如此,
因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当⽗加载器反馈⾃⼰
⽆法完成这个加载请求时,⼦加载器才会尝试⾃⼰去完成加载。
答案是为了保证应⽤程序的稳定有序。
例如类java.lang.Object,它存放在rt.jar之中,通过双亲委派机制,保证最终都是委派给处于模
型最顶端的启动类加载器进⾏加载,保证Object的⼀致。反之,都由各个类加载器⾃⾏去加载
的话,如果⽤户⾃⼰也编写了⼀个名为java.lang.Object的类,并放在程序的 ClassPath中,那系
统中就会出现多个不同的Object类。
47.如何破坏双亲委派机制?
如果不想打破双亲委派模型,就重写ClassLoader类中的fifindClass()⽅法即可,⽆法被⽗类加
载器加载的类最终会通过这个⽅法被加载。⽽如果想打破双亲委派模型则需要重写loadClass()
⽅法

Tomcat实际上也是破坏了双亲委派模型的。
Tomact是web容器,可能需要部署多个应⽤程序。不同的应⽤程序可能会依赖同⼀个第三⽅类
库的不同版本,但是不同版本的类库中某⼀个类的全路径名可能是⼀样的。如多个应⽤都要
依赖hollis.jar,但是A应⽤需要依赖1.0.0版本,但是B应⽤需要依赖1.0.1版本。这两个版本中
都有⼀个类是com.hollis.Test.class。如果采⽤默认的双亲委派类加载机制,那么⽆法加载多个
相同的类。
所以,Tomcat破坏了双亲委派原则,提供隔离的机制,为每个web容器单独提供⼀个
WebAppClassLoader加载器。每⼀个WebAppClassLoader负责加载本⾝的⽬录下的class⽂件,
加载不到时再交CommonClassLoader加载,这和双亲委派刚好相反。

小白学java-JVM知识点总结相关推荐

  1. java零基础多久能学会_小白学java大概需要多久 零基础学起来难么

    这取决于每天学习的时间.如果你每天花2-3个小时学习,大约需要半年时间.更重要的是,这取决于你学了多少.如果你想学一门基础知识,只需要几个月.如果你想深入学习,熟悉它,需要一年.两年甚至三五年的时间. ...

  2. 小白学java进阶工程师路线图

    原标题:小白学java进阶工程师路线图 Java小白如何成长为Java大牛?这9点你做到了几点! 给刚进社会的程序员新生一个建议,想成为一个优秀的程序员,高级程序员,不能眼高手低,不能认为开发新项目, ...

  3. 零基础小白学Java难度大不大

    零基础小白学Java难度大不大?有很多人都是非常关心这个问题的,如今java在IT互联网行业的快速发展,引起了很多人的注意,那么,哪些人适合入行Java?零基础学习Java难度大吗?下面,小编就为大家 ...

  4. 小白学Java Web 3 Web前端之CSS基本知识2

    这一篇接着上一篇的内容来分享,上一篇还有大量的样式属性没有列出,不过在继续分享之前,我想先来分享一下关于网页的布局相关的一些东西,因为下一篇我打算分 享用仅仅前面三小篇的内容来制作一个简单的静态网页, ...

  5. java编程好学么_零基础小白学Java编程好学吗

    Java是一门不会衰落的开发语言,伴随着IT行业的兴起,目前学习java培训的人员也是变得更多了,但要想学好java的话通过自学是没有那样非常容易的事情.尤其是对于初学者的学生而言,那么零基础小白学J ...

  6. 小白学Java 第14课:do while 循环

    [相关链接] 上一篇:小白学Java 第13课:while 循环 下一篇:小白学Java 第15课:方法介绍与调用 总纲:返回列表 上节课我们学习了while循环,他的结构格式为: while(条件) ...

  7. java 包装类可以被继承_小白学Java:包装类

    小白学Java:包装类 学习了许久的Java,我们知道Java是一种面向对象的语言,万物皆对象.但是我们之前在说到Java基本数据类型的时候,由于处理对象需要额外的系统开销,于是出于对性能的考虑,基本 ...

  8. 小白学JAVA之十八——泛型

    小白学JAVA之十八--泛型 一. 基本概念 通常情况下集合中可以存放不同类型的对象,是因为将所有对象都看做Object类型放入的,因此从集合中取出元素时也是Object类型,为了表达该元素真实的数据 ...

  9. 小白学JAVA之十七——集合类库

    小白学JAVA之十七--集合类库 一. 集合 1.1 集合的由来 当需要在Java程序中记录单个数据内容时,则声明一个变量. 当需要在Java程序中记录多个类型相同的数据内容时,声明一个一维数组. 当 ...

  10. (小白学JAVA之)Java高级特性知识点梳理

    Java高级特性知识点梳理 集合框架和泛型 List接口 ArrayList ArrayList类的常用方法 具体实现步骤 LinkedList LinkedList类的常用方法 具体实现步骤 Set ...

最新文章

  1. CSS 七层叠层顺序(stacking level)
  2. 看奥运之五:关于“鸟巢”、“水立方”的数据和内涵
  3. python声明编码为gbk_Python字符串编码坑彻底详细解决
  4. 在cmd命令行下编译运行C/C++源文件
  5. Android:IntentService的学习
  6. 前女友发来加密的 “520快乐.pdf“,我用python破解开之后,却发现。。。
  7. delphi windows编程_学习C/C++:伴随我成长的编程书!
  8. 常用Git客户端:Tower for Mac
  9. ROS1 robot path tracking
  10. POJ 3624 Charm Bracelet【01背包】
  11. 字节、字符输入输出流
  12. 五种常用源代码开源协议
  13. 解决家庭版win10、win8没有远程桌面选项
  14. 蒟蒻的网络流24题解题记
  15. 华为S5700交换机链路聚合配置
  16. C-11 Problem H: 开宝箱2
  17. 在计算机领域,美国信息交换标准代码的缩写符号是.,计算机基础在线作业.docx...
  18. C语言试题164之求定积分
  19. 该死!辛苦制作的PDF文档被人随意传播,甚至还被拿去卖钱?
  20. 【leetcode】 剑指 Offer学习计划(java版本含注释)(上)

热门文章

  1. js 判断是企业微信或微信
  2. CyclicBarrier栅栏
  3. 计算机专业保研面试备考:高等数学
  4. 计算机用户文件夹怎么重命名,win10修改账户文件夹名方法_windows10用户文件夹改名怎么操作...
  5. 电脑能正常上网,但登不上 QQ
  6. Python案例实操3-电影数据分析
  7. 谷歌中国正式宣布李开复辞去总裁一职
  8. Apache中文URL中有包含“\x85”字节的汉字时导致的Rewrite失败及404问题
  9. 永中文档在线预览集群部署方案
  10. linux 挂载ISO镜像文件