回答重点Java 的 AOT(Ahead-Of-Time,预编译)是一种在程序运行之前,将 Java 字节码直接编译为本地机器码的技术。
JIT 是在 Java 运行时将一些代码编译成机器码,而 AOT 则是在代码运行之前就编译成机器吗,也就是提前编译。
提前编译的好处是减少运行时编译的开销,且减少程序启动所需的编译时间,提高启动速度。
扩展知识AOT 的工作原理:AOT 编译是在构建阶段对...
回答重点逃逸分析(Escape Analysis)是 Java 编译器的优化技术,用于确定一个对象的作用范围,即分析对象是否会逃逸出当前方法或线程的作用范围。如果对象不会逃逸,JVM 可以实现栈上分配、同步消除、标量替换等优化,减少内存分配开销和同步开销,从而提高应用的性能。
逃逸的两种类型:
方法逃逸:如果一个对象在方法内部创建,并作为返回值或通过参数传递给其他方法,则该对象会逃逸到方法...
回答重点分为新生代收集器和老年代收集器来看,常见的垃圾收集器包括:
新生代垃圾收集器:1)Serial 收集器:
单线程收集器,适合小型应用和单处理器环境。
触发 Stop-The-World(STW)操作,所有应用线程在 GC 时暂停。
适用场景:适用于单线程应用和客户端模式。
2)ParNew 收集器:
是 Serial 收集器的多线程版本,能够并行进行垃圾收集。
与 CMS 收集...
回答重点主要通过以下两种方式来实现:
1. 引用计数法(Reference Counting):
每个对象维护一个引用计数器,引用计数增加时,计数器加 1,减少时,计数器减 1。当引用计数器为 0 时,说明该对象不再被引用,可以被回收。
优点:实现简单,实时性好。
缺点:无法处理循环引用的问题,两个对象互相引用时,引用计数器永远不会为 0。
2. 可达性分析算法(Reachability ...
回答重点主要是为了提高垃圾回收效率,依据对象的生命周期特点来进行优化。
对象的生命周期特点:
大多数对象存活时间短:大部分对象会很快变成垃圾,不再被使用,这些短生命周期的对象会分配在新生代。
少部分对象存活时间长:一些长期存活的对象不会很快被回收,分配在新生代的对象经过多次垃圾回收仍存活的,将晋升到老年代。
所以按照存活时间分区管理更加高效,也因为不同分区的生命周期不同,所以可以采用不同...
回答重点三色标记算法 是现代垃圾回收器中常用的一种 增量标记算法,它通过“白-灰-黑”三种颜色标记对象的状态可以与应用线程并发执行的同时确保程序的内存管理安全。
它用于标记哪些对象需要被回收,哪些对象需要保留,减少一次性停顿带来的性能影响。非常适合 低延迟 和 实时垃圾回收 的场景。
它通过将对象分为三种颜色来进行标记和追踪。
三色标记的基本概念:
白色对象:表示还没有被垃圾回收器访问到的...
回答重点主要是为了提高新生代内存的利用率。
扩展知识详细分析因为新生代对象朝生夕死的特性,适合复制算法。按正常思路将新生代一分为二,划两块区域,每次只使用其中一个,GC 后将存活的复制到另一个区域,然后清理老区域非存活对象,这样替换使用两块区域可以避免内存碎片的存在。
但如果一分为二的话,空间利用率只有一半了(每次分配对象只能占据一半的内存大小),这样不太划算。
基于这点,定义了三个区...
回答重点Young GC(Minor GC 或 YGC),即年轻代垃圾回收:
作用范围:仅针对新生代(Eden 和 S0/S1)。
触发条件:当新生代内存(尤其是 Eden 区)被填满时触发。
执行方式:只回收新生代中的对象,老年代不受影响。
特点:回收频率较高,回收时间较短,因为新生代中的对象大多数是短命对象,容易被回收。
Old GC(Major GC 或 OGC),老年代...
回答重点在 Java 中,Young GC(Minor GC) 是针对新生代(Young Generation)对象的垃圾回收。
主要有三种情况会会触发 Young GC:
1)Eden 区空间不足:
新生代被划分为三个区域:Eden 区、S0(Survivor 0) 区和 S1(Survivor 1) 区。大部分新创建的对象会先分配到 Eden 区。
当 Eden 区的对象填满,无法再为...
回答重点以下几种情况可能会触发 Full GC:
1)老年代空间不足:
当老年代空间不足时(且无法通过老年代垃圾回收释放足够空间),会触发 Full GC 来回收老年代中的对象。
2)永久代或元空间空间不足:
在 Java 8 之前,如果永久代(PermGen)空间不足,会触发 Full GC。Java 8 之后,永久代被移除,元空间(Metaspace)取代了永久代。如果元空间(设置...
回答重点TLAB(Thread-Local Allocation Buffer)是 JVM 中为每个线程分配的一小块堆内存,用于加速对象的分配操作。每个线程都有自己的 TLAB,,大大加速了内存分配的同时避免了多线程竞争共享堆内存时的同步开销。
工作原理:
每个线程在执行过程中优先从自己的 TLAB 中分配内存。
当 TLAB 中的内存耗尽时,线程会重新向 Eden 区申请一个新的 TLA...
回答重点PLAB(Promotion Local Allocation Buffer) 是 Java 垃圾回收器中的一种优化机制,主要用于 G1 垃圾收集器,目的是提高对象晋升(Promotion)到老年代时的效率。
在垃圾回收过程中,新生代中的某些对象由于生命周期较长,会被晋升到老年代。为了减少线程竞争和提升晋升效率,G1 为每个 GC 线程分配一个局部缓冲区,称为 PLAB。每个线程可以...
回答重点concurrent mode failure 是在 Java 虚拟机使用 CMS(Concurrent Mark-Sweep)垃圾收集器 时的一种失败现象。当 CMS 在执行垃圾回收时,发现内存中的老年代(Old Generation)空间不足以继续分配新对象时,导致垃圾回收被迫转为 Full GC。
产生的原因:
CMS 收集器是并发进行的,意味着它会与应用线程同时运行。然而,...
**以下的回答来自 R 大 **。
因为没足够开发资源,偷懒了。就这么简单。没有任何技术上的问题。 大公司都自己内部做了优化。
所以最初怎么会偷这个懒的呢?多灾多难的CMS GC经历了多次动荡。它最初是作为Sun Labs的Exact VM的低延迟GC而设计实现的。
但 Exact VM在与 HotSpot VM争抢 Sun 的正牌 JVM 的内部斗争中失利,CMS GC 后来就作为 Exa...
回答重点
这张图是 2008 年 HostSpot 一位 GC 组成员画的,那时候 G1 还没问世,在研发中,所以画了个问号在上面。
里面的回答是 :
“ParNew” is written in a style… “Parallel Old” is not written in the “ParNew” style
HotSpot VM 自身的分代收集器实现有一套框架,只有在框架内的...
回答重点JVM 在进行新生代垃圾回收时,通过以下方式避免全堆扫描:
1)卡表(Card Table)机制:JVM 使用卡表记录老年代引用新生代对象的指针变化,从而在进行新生代回收时,只扫描那些老年代中确实有引用指向新生代的区域,避免了全堆扫描。
2)写屏障(Write Barrier):当老年代中的对象引用新生代对象时,写屏障会拦截这种引用,并在卡表中标记相关信息。这样,垃圾回收器在扫描时只...
回答重点CMS 垃圾回收器:
CMS 使用卡表(Card Table,记忆集的一种实现) 来记录老年代中引用新生代的对象。卡表的维护较为简单,老年代对象指向新生代对象时,会触发写屏障并标记相应的卡片。
CMS 的卡表是通过写屏障维护的,当老年代对象引用新生代对象时,CMS 会在卡表中将对应区域标记为“脏卡”,以便在 GC 时扫描这些区域。
G1 垃圾回收器:
G1 的记忆集(Remem...
回答重点G1 分了 young GC 和 mixed gc。
young gc 会选取所有年轻代的 region 进行收集。
midex gc 会选取所有年轻代的 region 和一些收集收益高的老年代 region 进行收集。
所以年轻代的 region 都在收集范围内,因此不需要额外记录年轻代到老年代的跨代引用。
回答重点CMS 和 G1 分别通过增量更新(Incremental update)和 SATB(snapshot-at-the-beginning)来打破这两个充分必要条件,维持了 GC 线程与应用线程并发的正确性。
并发执行可能出现对象漏标,而漏标的两个充分必要条件是:
1)将新对象插入已扫描完毕的对象中,即插入黑色对象到白色对象的引用。
2)删除了灰色对象到白色对象的引用。
CMS 用了...
回答重点Java 中的 logging write barrier(日志写屏障)是一种与垃圾回收(GC)相关的机制,主要用于追踪和记录对象引用的变化,特别是在并发和增量式垃圾回收过程中。通过 write barrier,在应用程序运行期间,垃圾收集器可以检测对象的引用关系何时发生变化,从而维护记忆集或卡表等数据结构,避免全堆扫描。
作用:
减少对应用程序的影响:写屏障会消耗应用程序的性能,...
回答重点G1 从大局上看分为两大阶段,分别是并发标记和对象拷贝。
并发标记并发标记是基于 SATB 的,可以分为四大阶段:
**1)初始标记(initial marking)**,这个阶段是 STW 的,扫描根集合,标记根直接可达的对象即可。在G1中标记对象是利用外部的bitmap来记录,而不是对象头。
2、并发阶段(concurrent marking),这个阶段和应用线程并发,从上一步标...
回答重点1)初始标记(initial mark)
在这个阶段,CMS 会进行一个快速的初始标记,标记所有根对象(如栈中的引用)直接可达的对象。此过程是 STW的,但时间较短。
2)并发标记(Concurrent marking)
初始标记后,CMS 进入并发标记阶段。在此阶段,垃圾收集器与应用线程并发运行,从上一步标记的根直接可达对象开始进行 tracing,递归扫描所有可达对象。此阶...
回答重点ZGC(Z Garbage Collector)是Java 11引入的低延迟垃圾回收器,旨在支持大内存(可以高达数 TB)的应用程序,并保持短的GC停顿时间。
主要特点:
并发收集:ZGC的收集过程大部分是在应用线程运行的同时进行,最大限度地减少了停顿时间。
指针压缩:使用指针压缩技术,减少内存占用并提高性能。
无停顿(或极小停顿):GC的停顿时间通常在毫秒级,对于大多数应用来说几...
回答重点分别是最短暂停时间和高吞吐量。
最短暂停时间:垃圾回收调优的首要目标是减少应用程序的停顿时间,确保在垃圾回收过程中尽量保持应用的响应能力,特别是对于实时或高并发应用。
高吞吐量:第二个目标是提高应用的吞吐量,即在单位时间内完成更多的业务处理。通过合理的GC策略和配置,减少GC的频率和时间,从而提升整体性能。
针对最短暂停时间和高吞吐举个例子:
方案一:每次 GC 停顿 100 m...
回答重点
GC 调优这种问题肯定是具体场景具体分析,但是在面试中就不要讲太细,大方向说清楚就行,不需要涉及具体的垃圾收集器比如 CMS 调什么参数,G1 调什么参数之类的。
GC 调优的核心思路就是尽可能的使对象在年轻代被回收,减少对象进入老年代。
具体调优还是得看场景根据 GC 日志具体分析,常见的需要关注的指标是 Young GC 和 Full GC 触发频率、原因、晋升的速率、老年代...
回答重点
-Xms:初始化堆内存大小
-Xmx:最大堆内存大小
-Xss:设置每个线程的栈大小
-XX:MetaspaceSize:初始化元空间大小
-XX:MaxMetaspaceSize:最大元空间大小
-XX:+HeapDumpOnOutOfMemoryError:当发生 OutOfMemoryError 时,生成堆转储(heap dump)
-XX:+PrintGCDetails:打...
回答重点
jmap:用于生成堆转储的命令行工具,可以用于分析JVM内存使用情况,尤其是内存泄漏问题
jstack:用于生成线程转储的命令行工具,可以用于分析线程状态,排查死锁等问题
jstat:用于监控JVM统计信息的命令行工具,提供了实时的性能数据,如类加载、垃圾回收、编译器等信息
MAT:用于分析堆转储文件的工具,可以帮助识别内存泄漏和优化内存使用
jconsole:可以监控JVM的内存...
回答重点先确认是否真的发生了内存泄漏,即观察内存使用情况。
利用 jstat 命令(jstat -gc <pid> <interval in ms> )来观察 gc 概要信息,如果发现 GC 后内存并没有明显的减少且还是持续增加持续触发 gc,那说明内存泄漏的概率很大。
此时可以利用 jmap(jmap -dump:format=b,file=heapdump.hpr...
回答重点Java 7 及之前的方法区被实现为永久代(PermGen)中,它是固定大小的内存区域,不能动态扩展。如果加载的类过多或常量池的数据过多,超出了永久代的限制,就会出现 OutOfMemoryError: PermGen space 错误。
在 Java 8 及之后,方法区改用元空间(Metaspace)来代替永久代。元空间不再使用堆内存,而是使用本地内存(Native Memory)...
回答重点Java 中常见的 OOM 情况可以概括为以下几种:
OOM 错误类型
原因
常见解决方法
Java Heap Space
堆内存不足,常见于大量对象创建
优化对象使用或增大堆内存
StackOverflowError
栈空间耗尽,常见于递归或深层嵌套调用
优化递归逻辑或增大栈空间
PermGen Space / Metaspace
方法区或元空间不足,...