JAVA面试题、八股文学习之JVM篇

1.什么是空闲列表?

空闲列表(Free List) 是一种内存管理技术,主要用于跟踪和管理堆内存中可用的空闲块。它广泛应用于各种内存分配算法中,特别是在 分段分配(Segmented Allocation) 和 链式分配(Linked Allocation) 策略中。下面详细介绍空闲列表的工作原理及其特点。

空闲列表的基本概念

空闲列表是一种数据结构,用于维护堆内存中所有未被使用的内存块的信息。每个空闲块通常包含以下信息:

  • 起始地址:该空闲块在内存中的起始位置。
  • 大小:该空闲块的字节数。
  • 下一个空闲块指针:指向列表中的下一个空闲块。

通过维护这样一个列表,内存分配器可以快速找到合适的空闲块来满足对象的分配请求,并在释放对象时将相应的内存块重新加入到空闲列表中。

工作原理

  • 初始化
    • 当 JVM 启动时,整个堆内存被视为一个大的空闲块,并将其添加到空闲列表中。
  • 对象分配
    • 当需要创建新对象时,内存分配器会遍历空闲列表,查找足够大的空闲块。
    • 如果找到合适的空闲块,则从该块中分配所需的空间,并更新空闲列表。
    • 如果找不到合适的大块,则可能需要触发垃圾回收或调整堆大小。
  • 空闲块分割
    • 为了提高内存利用率,分配器可能会将较大的空闲块分割成两部分:一部分用于分配对象,另一部分保留在空闲列表中作为新的空闲块。
  • 合并相邻空闲块
    • 当释放对象时,相应的内存块会被标记为空闲,并尝试与相邻的空闲块合并,以减少碎片化。
  • 更新空闲列表
    • 分配和释放操作都会导致空闲列表的变化。分配操作会移除或缩小某个空闲块,而释放操作会添加新的空闲块或合并现有块。

示例图解

假设有一个简单的堆内存结构如下:

+-------------------+
|       Free        |  Size: 100 bytes
|                   |
|                   |
+-------------------+
|      Allocated    |  Size: 50 bytes
|                   |
+-------------------+
|       Free        |  Size: 75 bytes
|                   |
+-------------------+

对应的空闲列表可能如下:

+-------------------+
|  Start Address: 0x1000  |
|  Size: 100 bytes     |
|  Next: 0x10080         |
+-------------------+
|  Start Address: 0x100D0 |
|  Size: 75 bytes      |
|  Next: null            |
+-------------------+

分配对象 A (Size: 30 bytes)

  • 查找空闲块:
    • 查找第一个空闲块(Start Address: 0x1000, Size: 100 bytes),其大小足够分配对象 A。
  • 分配空间:
    • 从该空闲块中分配 30 字节的空间给对象 A。
    • 更新空闲块的起始地址和大小。
  • 更新空闲列表:
    • 修改第一个空闲块的起始地址为 0x1001E,大小变为 70 bytes。

结果如下:

+-------------------+
|       Free        |  Size: 70 bytes
|                   |
|                   |
+-------------------+
|      Allocated    |  Size: 30 bytes
|      [A]          |
+-------------------+
|      Allocated    |  Size: 50 bytes
|                   |
+-------------------+
|       Free        |  Size: 75 bytes
|                   |
+-------------------+

对应的空闲列表如下:

+-------------------+
|  Start Address: 0x1001E |
|  Size: 70 bytes       |
|  Next: 0x10080          |
+-------------------+
|  Start Address: 0x10080 |
|  Size: 75 bytes       |
|  Next: null             |
+-------------------+

释放对象 A

  • 标记为空闲:
    • 将对象 A 所占的空间标记为空闲。
  • 合并相邻空闲块:
    • 检查相邻的空闲块,发现前一个空闲块(Start Address: 0x1001E, Size: 70 bytes)和当前释放的块可以合并。
    • 合并这两个空闲块,形成一个新的空闲块。
  • 更新空闲列表:
    • 移除旧的空闲块,并更新合并后的空闲块信息。

结果如下:

+-------------------+
|       Free        |  Size: 100 bytes
|                   |
|                   |
+-------------------+
|      Allocated    |  Size: 50 bytes
|                   |
+-------------------+
|       Free        |  Size: 75 bytes
|                   |
+-------------------+

对应的空闲列表如下:

+-------------------+
|  Start Address: 0x1000  |
|  Size: 100 bytes     |
|  Next: 0x10080         |
+-------------------+
|  Start Address: 0x10080 |
|  Size: 75 bytes      |
|  Next: null            |
+-------------------+

特点和优势

  • 高效性
    • 空闲列表允许快速查找和分配空闲块,适合动态内存分配场景。
  • 灵活性
    • 可以灵活地处理不同大小的对象分配请求。
  • 简单实现
    • 相比于其他复杂的内存管理策略,空闲列表的实现相对简单。
  • 降低碎片化
    • 通过合并相邻的空闲块,可以有效减少内存碎片化。

注意事项

  • 碎片化问题:
    • 即使使用空闲列表,长时间运行的应用程序也可能出现内存碎片化的问题。
    • 定期进行垃圾回收可以帮助减少碎片化。
  • 搜索时间:
    • 在大型堆中,查找合适的空闲块可能会消耗较多的时间。
    • 可以采用不同的搜索策略(如最佳适应、首次适应等)来优化性能。
  • 锁竞争:
    • 在多线程环境中,访问空闲列表可能导致锁竞争。
    • 可以使用细粒度锁或多线程友好的分配策略来缓解这个问题。

总结

空闲列表是一种有效的内存管理技术,广泛应用于各种内存分配算法中。通过维护一个记录所有空闲块的数据结构,它可以快速地分配和释放内存,从而提高内存利用率和系统性能。

2.什么是TLAB ?

TLAB(Thread Local Allocation Buffer) 是 Java 虚拟机(JVM)中的一种优化技术,主要用于提高多线程环境下对象分配的性能。通过将每个线程的对象分配空间独立化,TLAB 减少了线程间竞争和锁的开销,从而提升了整体吞吐量。下面详细介绍 TLAB 的工作原理及其优势。

TLAB 的基本概念

TLAB 是为每个线程预先分配的一小块内存区域,专门用于该线程创建的对象。当一个线程需要创建新对象时,它首先尝试从自己的 TLAB 中分配内存。只有在 TLAB 不足时,才会请求更多的内存或从共享的堆内存中分配。

工作原理

  • 初始化:
    • 当 JVM 启动并创建线程时,会为每个线程分配一个 TLAB。
    • TLAB 的大小可以根据 JVM 参数进行配置,默认情况下由 JVM 自动调整。
  • 对象分配:
    • 线程在创建新对象时,首先检查其 TLAB 是否有足够的空间。
    • 如果有足够空间,则直接在 TLAB 中分配对象,并移动 TLAB 的顶部指针。
    • 如果没有足够空间,则向全局堆请求新的 TLAB 或者直接从堆中分配对象。
  • TLAB 回收:
    • 当 TLAB 被耗尽时,线程会请求一个新的 TLAB。
    • 旧的 TLAB 中的对象会被标记为存活,后续会被垃圾回收器处理。
  • 动态调整:
    • JVM 可以根据实际使用情况动态调整 TLAB 的大小,以平衡分配效率和内存利用率。

示例图解

假设有一个简单的多线程环境,有两个线程 Thread A 和 Thread B,各自拥有一个 TLAB:

+-------------------+
|    Thread A       |
|  +-------------+  |
|  |     TLAB    |  |
|  | [Object 1]  |  |
|  | [Object 2]  |  |
|  +-------------+  |
+-------------------++-------------------+
|    Thread B       |
|  +-------------+  |
|  |     TLAB    |  |
|  | [Object 3]  |  |
|  |             |  |
|  +-------------+  |
+-------------------+

分配对象 C (Size: 10 bytes) 到 Thread A

  • 检查 TLAB 空间
    • Thread A 检查其 TLAB 是否有足够的空间来分配对象 C(10 bytes)。
    • 假设 TLAB 还有足够的空间。
  • 分配对象 C
    • 在 TLAB 中分配 10 字节的空间给对象 C。
    • 移动 TLAB 的顶部指针。

结果如下:

+-------------------+
|    Thread A       |
|  +-------------+  |
|  |     TLAB    |  |
|  | [Object 1]  |  |
|  | [Object 2]  |  |
|  | [Object C]  |  |
|  +-------------+  |
+-------------------++-------------------+
|    Thread B       |
|  +-------------+  |
|  |     TLAB    |  |
|  | [Object 3]  |  |
|  |             |  |
|  +-------------+  |
+-------------------+

分配对象 D (Size: 50 bytes) 到 Thread B

  • 检查 TLAB 空间
    • Thread B 检查其 TLAB 是否有足够的空间来分配对象 D(50 bytes)。
    • 假设 TLAB 不足以容纳对象 D。
  • 请求新的 TLAB 或直接分配
    • Thread B 请求一个新的 TLAB 或者直接从全局堆中分配对象 D。

结果如下:

+-------------------+
|    Thread A       |
|  +-------------+  |
|  |     TLAB    |  |
|  | [Object 1]  |  |
|  | [Object 2]  |  |
|  | [Object C]  |  |
|  +-------------+  |
+-------------------++-------------------+
|    Thread B       |
|  +-------------+  |
|  |     TLAB    |  |
|  | [Object D]  |  |
|  |             |  |
|  +-------------+  |
+-------------------+

特点和优势

  • 减少锁竞争
    • 每个线程都有自己独立的 TLAB,减少了对全局堆锁的竞争。
    • 大多数对象分配都在本地完成,降低了锁的开销。
  • 提高分配速度
    • 使用指针碰撞(Pointer Bumping)技术,在 TLAB 中分配对象非常高效。
    • 避免了频繁的锁获取和释放操作,提高了对象分配的速度。
  • 降低碎片化
    • TLAB 中的对象通常是连续分配的,减少了内存碎片化的问题。
    • 有利于提高缓存命中率,提升整体性能。
  • 动态调整
    • JVM 可以根据实际应用的需求动态调整 TLAB 的大小。
    • 适应不同的应用场景,优化内存分配策略。

配置参数

JVM 提供了一些参数来控制 TLAB 的行为:

  • -XX:+UseTLAB:启用 TLAB(默认启用)。
  • -XX:-UseTLAB:禁用 TLAB。
  • -XX:TLABSize=:设置 TLAB 的初始大小。
  • -XX:TLABRefillWasteFraction=:设置 TLAB 再填充浪费分数。
  • -XX:MinTLABSize=:设置 TLAB 的最小大小。
  • -XX:MaxTLABSize=:设置 TLAB 的最大大小。

注意事项

  • 线程数量:
    • 如果线程数量过多,可能会导致大量的 TLAB 分配,增加管理开销。
    • 需要根据实际情况调整线程池大小和 TLAB 参数。
  • 对象大小:
    • 对于非常大的对象,通常不会分配到 TLAB,而是直接从全局堆中分配。
    • 需要注意大对象的分配策略,避免不必要的性能开销。
  • 垃圾回收:
    • TLAB 中的对象在 TLAB 被耗尽后会被标记为存活,参与垃圾回收过程。
    • 适当的 TLAB 大小可以帮助减少垃圾回收的压力。

总结

TLAB 是一种重要的内存分配优化技术,通过为每个线程分配独立的内存区域,显著提高了多线程环境下对象分配的性能。通过减少锁竞争、提高分配速度和降低碎片化,TLAB 成为现代 JVM 中不可或缺的一部分。

3.对象头具体都包含哪些内容?

在 Java 虚拟机(JVM)中,对象头(Object Header) 是每个对象都必须包含的一个部分,用于存储与对象相关的重要元数据信息。对象头的结构和内容因 JVM 的具体实现而异,但通常包含以下几个关键部分:

对象头的基本结构

Java 对象头主要由两部分组成:

  • Mark Word:用于存储对象的运行时数据。
  • Klass Pointer:指向对象所属类的元数据(在某些情况下可以省略)。

1. Mark Word

Mark Word 是对象头中最重要的一部分,用于存储对象的状态信息、哈希码、GC 状态、锁状态等。具体的结构取决于 JVM 的实现,以下是一些常见的字段:

  • Hashcode:对象的哈希码值,用于 hashCode() 方法。
  • Age:对象的年龄,用于判断对象是否需要晋升到老年代。
  • Biased Locking:偏向锁的信息,用于轻量级锁优化。
  • Lock Status:对象的锁定状态,包括无锁、偏向锁、轻量级锁、重量级锁等。
  • GC Metadata:垃圾回收相关的标志位,如可达性标记等。
  • Thread ID:持有偏向锁的线程 ID。
  • Epoch:偏向锁的时间戳或版本号。

2. Klass Pointer

Klass Pointer 指向对象所属类的元数据(klass 结构),包含了类的详细信息,如父类、方法表、字段信息等。在某些情况下,特别是压缩指针启用的情况下,Klass Pointer 可能被省略或合并到 Mark Word 中。

具体示例

以下是一个典型的 64 位 JVM 中对象头的结构示意图:

+--------------------------------------------------+
|                    Mark Word                     |
|--------------------------------------------------|
| Hashcode | Age | Biased Locking | Lock Status    |
+--------------------------------------------------+
|                 Klass Pointer                    |
+--------------------------------------------------+

Mark Word 的详细结构

在不同的 JVM 实现中,Mark Word 的具体结构可能会有所不同。以下是 HotSpot JVM 中的一种常见结构:

+--------------------------------------------------+
| hashcode:25 | age:4 | biased_lock:1 | lock:2     |
+--------------------------------------------------+
| thread_id:54 | epoch:2                          |
+--------------------------------------------------+
  • hashcode:25:对象的哈希码值。
  • age:4:对象的年龄,用于分代垃圾回收。
  • biased_lock:1:表示是否启用了偏向锁。
  • lock:2:表示对象的锁定状态(0b00 表示无锁,0b01 表示偏向锁,0b10 表示轻量级锁,0b11 表示重量级锁)。
  • thread_id:54:持有偏向锁的线程 ID。
  • epoch:2:偏向锁的时间戳或版本号。

压缩指针

为了节省内存,现代 JVM 通常会启用压缩指针(Compressed Pointers)。压缩指针技术通过使用较小的指针大小来减少内存占用。例如,在 64 位 JVM 上,Klass Pointer 和普通对象引用可以被压缩为 32 位。

启用压缩指针

可以通过以下 JVM 参数启用压缩指针:

  • -XX:+UseCompressedOops:启用压缩对象指针。
  • -XX:+UseCompressedClassPointers:启用压缩类指针。

示例代码

虽然对象头的内容不能直接通过 Java 代码访问,但我们可以通过一些工具和技术来观察和分析对象头的信息。例如,使用 jol-core 库可以查看对象头的布局和大小。

[<title="使用 jol-core 查看对象头信息">]
import org.openjdk.jol.info.ClassLayout;public class ObjectHeaderExample {public static void main(String[] args) {MyClass obj = new MyClass();System.out.println(ClassLayout.parseInstance(obj).toPrintable());}
}class MyClass {private int value;
}

运行上述代码,输出可能如下所示:

com.example.ObjectHeaderExample$MyClass object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0    12        (object header)                           N/A12     4   int MyClass.value                             N/A16     4        (loss due to the next object alignment)
Instance size: 20 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

在这个输出中,(object header) 部分代表了对象头的大小和内容。

总结

Java 对象头是每个对象不可或缺的一部分,包含了对象的运行时元数据信息。主要包括 Mark Word 和 Klass Pointer 两个部分。Mark Word 存储了对象的状态信息、哈希码、GC 状态、锁状态等,而 Klass Pointer 指向对象所属类的元数据。通过理解对象头的结构和内容,可以更好地掌握 JVM 内存管理和对象生命周期的相关知识。

4.你知道哪些JVM调优参数?

JVM 调优参数是用于调整 Java 虚拟机的行为和性能的关键设置。通过合理配置这些参数,可以显著提升应用程序的性能、稳定性和资源利用率。以下是一些常用的 JVM 调优参数及其作用:

堆内存调优参数

    1. 初始堆大小 (-Xms)
    • 作用:设置 JVM 启动时分配的初始堆内存大小。

示例:

-Xms512m
    1. 最大堆大小 (-Xmx)
    • 作用:设置 JVM 允许的最大堆内存大小。

示例:

-Xmx2g
  • 3. 新生代大小 (-Xmn)
    • 作用:设置新生代(Young Generation)的大小。

示例:

-Xmn768m
  • 4. 年轻代 Eden 区大小 (-XX:NewRatio)
    • 作用:设置年轻代中 Eden 区与 Survivor 区的比例。默认值为 2,表示 Eden 区占 2/3,每个 Survivor 区占 1/6。

示例:

-XX:NewRatio=3
    1. Survivor 区比例 (-XX:SurvivorRatio)
    • 作用:设置 Eden 区与 Survivor 区的比例。默认值为 8,表示 Eden 区占 8/10,每个 Survivor 区占 1/10。

示例:

-XX:SurvivorRatio=6
  • 6. 压缩指针 (-XX:+UseCompressedOops)
    • 作用:启用压缩对象指针,减少 64 位 JVM 中的对象引用大小。

示例:

-XX:+UseCompressedOops
  • 7. 压缩类指针 (-XX:+UseCompressedClassPointers)
    • 作用:启用压缩类指针,减少 64 位 JVM 中的类引用大小。

示例:

-XX:+UseCompressedClassPointers

垃圾回收调优参数

  • 1. G1 垃圾收集器 (-XX:+UseG1GC)
    • 作用:启用 G1 垃圾收集器。

示例:

-XX:+UseG1GC
  • 2. CMS 垃圾收集器 (-XX:+UseConcMarkSweepGC)
    • 作用:启用 CMS(Concurrent Mark Sweep)垃圾收集器。

示例:

-XX:+UseConcMarkSweepGC
  • 3. Parallel GC (-XX:+UseParallelGC)
    • 作用:启用 Parallel GC(并行垃圾收集器)。

示例:

-XX:+UseParallelGC
  • 4. Parallel Old GC (-XX:+UseParallelOldGC)
    • 作用:启用 Parallel Old GC(并行老年代垃圾收集器)。

示例:

-XX:+UseParallelOldGC
  • 5. Young GC 线程数 (-XX:ParallelGCThreads)
    • 作用:设置 Young GC 使用的线程数。

示例:

-XX:ParallelGCThreads=4
  • 6. Old GC 线程数 (-XX:ConcGCThreads)
    • 作用:设置 Concurrent GC 使用的线程数。

示例:

-XX:ConcGCThreads=2
  • 7. G1 Region 大小 (-XX:G1HeapRegionSize)
    • 作用:设置 G1 垃圾收集器中每个 region 的大小。

示例:

-XX:G1HeapRegionSize=16m
  • 8. G1 并发标记线程数 (-XX:ConcGCThreads)
    • 作用:设置 G1 并发标记阶段使用的线程数。

示例:

-XX:ConcGCThreads=4
  • 9. G1 Initiating Heap Occupancy Percent (-XX:InitiatingHeapOccupancyPercent)
    • 作用:设置触发并发标记周期的堆占用百分比。

示例:

-XX:InitiatingHeapOccupancyPercent=45

内存映射文件调优参数

  • 1. Metaspace 大小 (-XX:MetaspaceSize)
    • 作用:设置 Metaspace 的初始大小。

示例:

-XX:MetaspaceSize=256m
  • 2. 最大 Metaspace 大小 (-XX:MaxMetaspaceSize)
    • 作用:设置 Metaspace 的最大大小。

示例:

-XX:MaxMetaspaceSize=512m
  • 3. PermGen 大小 (-XX:PermSize 和 -XX:MaxPermSize)
    • 作用:设置永久代(PermGen)的初始和最大大小(已弃用,推荐使用 Metaspace)。

示例:

-XX:PermSize=128m
-XX:MaxPermSize=256m

其他常用参数

  • 1. 禁用偏向锁 (-XX:-UseBiasedLocking)
    • 作用:禁用偏向锁。

示例:

-XX:-UseBiasedLocking
  • 2. 启用逃逸分析 (-XX:+DoEscapeAnalysis)
    • 作用:启用逃逸分析优化。

示例:

-XX:+DoEscapeAnalysis
  • 3. 禁用逃逸分析 (-XX:-DoEscapeAnalysis)
    • 作用:禁用逃逸分析优化。

示例:

-XX:-DoEscapeAnalysis
  • 4. 启用 JIT 编译器 (-client 或 -server)
    • 作用:选择客户端或服务器模式的 JIT 编译器。

示例:

-client
-server
  • 5. 日志输出 (-Xloggc:)
    • 作用:将垃圾回收日志输出到指定文件。

示例:

-Xloggc:/path/to/gc.log
  • 6. 输出详细 GC 日志 (-verbose:gc)
    • 作用:输出详细的垃圾回收日志信息。

示例:

-verbose:gc
  • 7. 设置 GC 日志格式 (-XX:+PrintGCDetails)
    • 作用:打印详细的 GC 日志信息。

示例:

-XX:+PrintGCDetails
  • 8. 设置 GC 日志时间戳 (-XX:+PrintGCTimeStamps)
    • 作用:在 GC 日志中添加时间戳。

示例:

-XX:+PrintGCTimeStamps
  • 9. 设置 GC 日志日期戳 (-XX:+PrintGCDateStamps)
    • 作用:在 GC 日志中添加日期时间戳。

示例:

-XX:+PrintGCDateStamps
  • 10. 设置 GC 日志轮转 (-XX:+UseGCLogFileRotation)
    • 作用:启用 GC 日志文件轮转。

示例:

-XX:+UseGCLogFileRotation
  • 11. 设置 GC 日志文件数量 (-XX:NumberOfGCLogFiles)
    • 作用:设置 GC 日志文件的数量。

示例:

-XX:NumberOfGCLogFiles=5
  • 12. 设置 GC 日志文件大小 (-XX:GCLogFileSize)
    • 作用:设置每个 GC 日志文件的大小。

示例:

-XX:GCLogFileSize=10M
  • 13. 设置线程堆栈大小 (-Xss)
    • 作用:设置每个线程的堆栈大小。

示例:

-Xss1m
  • 14. 设置最大直接内存大小 (-XX:MaxDirectMemorySize)
    • 作用:设置 JVM 可以使用的最大直接内存大小。

示例:

-XX:MaxDirectMemorySize=256m
  • 15. 设置最大内联方法大小 (-XX:MaxInlineSize)
    • 作用:设置方法内联的最大字节码大小。

示例:

-XX:MaxInlineSize=35
  • 16. 设置最大内联层次深度 (-XX:MaxRecursiveInlineLevel)
    • 作用:设置递归内联的最大层次深度。

示例:

-XX:MaxRecursiveInlineLevel=1
  • 17. 设置最大内联方法大小 (-XX:LargeMethodThreshold)
    • 作用:设置认为是“大”方法的阈值字节数。

示例:

-XX:LargeMethodThreshold=32768
  • 18. 启用 TLAB (-XX:+UseTLAB)
    • 作用:启用 Thread Local Allocation Buffers (TLAB)。

示例:

-XX:+UseTLAB
  • 19. 设置 TLAB 大小 (-XX:TLABSize)
    • 作用:设置 TLAB 的初始大小。

示例:

-XX:TLABSize=1m
  • 20. 设置 TLAB 最大浪费比例 (-XX:TLABRefillWasteFraction)
    • 作用:设置 TLAB 再填充时允许的最大浪费比例。

示例:

-XX:TLABRefillWasteFraction=64

示例

以下是一个综合示例,展示了如何配置一些常用的 JVM 调优参数:

java -Xms512m -Xmx2g -Xmn768m -XX:NewRatio=3 -XX:SurvivorRatio=6 \-XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:ConcGCThreads=4 \-XX:InitiatingHeapOccupancyPercent=45 -XX:+UseCompressedOops \-XX:+UseCompressedClassPointers -XX:MetaspaceSize=256m \-XX:MaxMetaspaceSize=512m -XX:+DoEscapeAnalysis -XX:+UseTLAB \-Xss1m -Xloggc:/path/to/gc.log -verbose:gc -XX:+PrintGCDetails \-XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation \-XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M MyApplication

5.说一下 JVM 有哪些垃圾回收器?

Java 虚拟机(JVM)提供了多种垃圾回收器(Garbage Collectors),每种垃圾回收器都有其独特的特性和适用场景。以下是 JVM 中常见的几种垃圾回收器及其详细说明:

1. Serial Garbage Collector

适用场景:

  • 单线程环境。
  • 简单的应用程序或小型系统。

特点:

  • 单线程:使用单个线程进行垃圾回收,会导致应用程序在垃圾回收期间暂停(Stop-The-World, STW)。
  • 简单高效:适用于内存较小且不需要高并发的应用程序。
  • 低开销:由于只有一个线程参与垃圾回收,开销较低。

启用参数:

-XX:+UseSerialGC

示例

java -XX:+UseSerialGC MyApplication

2. Parallel Garbage Collector (Throughput Collector)

适用场景:

  • 多核处理器。
  • 需要高吞吐量的应用程序。
  • 对延迟要求不高。

特点:

  • 多线程:使用多个线程并行执行垃圾回收,减少 STW 时间。
  • 高吞吐量:适合需要最大化 CPU 使用率的批处理作业。
  • 可配置性:可以通过参数调整线程数和堆大小。

启用参数:

-XX:+UseParallelGC

示例

java -XX:+UseParallelGC -XX:ParallelGCThreads=4 -Xmx2g MyApplication

3. Concurrent Mark-Sweep (CMS) Garbage Collector

适用场景:

  • 需要低延迟的应用程序。
  • 实时系统或交互式应用。
  • 内存较大且对停顿时间敏感。

特点:

  • 并发收集:大部分工作在应用程序运行时并发执行,减少 STW 时间。
  • 低停顿:适合需要快速响应的应用程序。
  • 碎片化问题:长时间运行可能导致严重的内存碎片化。
  • 已弃用:从 JDK 9 开始,CMS 收集器已被标记为过时,并将在未来的版本中移除。

启用参数:

-XX:+UseConcMarkSweepGC

示例

java -XX:+UseConcMarkSweepGC -Xmx2g MyApplication

4. G1 Garbage Collector

适用场景:

  • 大型堆内存。
  • 需要平衡吞吐量和延迟的应用程序。
  • 对停顿时间有一定要求。

特点:

  • 分区收集:将堆内存划分为多个区域(regions),按需进行垃圾回收。
  • 并发与并行:结合了 CMS 和 Parallel GC 的优点,支持并发标记和并行清除。
  • 预测性:能够预测未来的停顿时间,动态调整回收行为。
  • 低停顿:适合需要低延迟的应用程序。
  • 自动调优:内置了许多自适应机制,减少了手动调优的需求。

启用参数:

-XX:+UseG1GC

示例

java -XX:+UseG1GC -Xmx4g -XX:MaxGCPauseMillis=200 MyApplication

5. Z Garbage Collector (ZGC)

适用场景:

  • 极大堆内存(数百 GB 到 TB)。
  • 对停顿时间有严格要求的实时系统。
  • 高吞吐量需求。

特点:

  • 低停顿:承诺不超过 10 毫秒的停顿时间,即使在大规模堆内存下也是如此。
  • 并发收集:几乎所有的垃圾回收工作都是并发执行的。
  • 压缩堆:消除内存碎片,提高内存利用率。
  • 低延迟:非常适合需要极低延迟的应用程序。
  • 实验性:从 JDK 11 开始引入,仍在不断发展和完善。

启用参数:

-XX:+UseZGC

示例

java -XX:+UseZGC -Xmx1t MyApplication

6. Shenandoah Garbage Collector

适用场景:

  • 大型堆内存。
  • 对停顿时间有严格要求的实时系统。
  • 高吞吐量需求。

特点:

  • 低停顿:承诺不超过 10 毫秒的停顿时间。
  • 并发收集:大多数垃圾回收工作是并发执行的。
  • 压缩堆:通过压缩技术减少内存碎片。
  • 无分代:采用不分代的设计,简化了垃圾回收过程。
  • 成熟稳定:经过多年的开发和优化,已在生产环境中广泛应用。

启用参数:

-XX:+UseShenandoahGC

示例

java -XX:+UseShenandoahGC -Xmx4g MyApplication

7. Epsilon Garbage Collector (NoOp GC)

适用场景:

  • 测试和基准测试。
  • 不需要垃圾回收的应用程序(如嵌入式系统)。

特点:

  • 无操作:不进行任何垃圾回收,适用于不需要垃圾回收的特殊场景。
  • 内存泄漏:如果不小心使用,可能会导致内存泄漏。
  • 简单高效:适用于简单的测试环境或特定应用场景。

启用参数:

-XX:+UseEpsilonGC

示例

java -XX:+UseEpsilonGC -Xmx512m MyApplication

总结

选择合适的垃圾回收器取决于具体的应用需求和硬件资源。以下是一些常见的选择建议:

  • 单线程或小型应用:使用 Serial GC。
  • 多核处理器、高吞吐量需求:使用 Parallel GC。
  • 低延迟、实时系统:考虑 G1 GC 或 Shenandoah GC。
  • 极大堆内存、超低延迟:使用 ZGC 或 Shenandoah GC。
  • 测试和基准测试:使用 Epsilon GC。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/478998.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电商项目高级篇06-缓存

电商项目高级篇06-缓存 1、docker下启动redis2、项目整合redis 缓存 流程图&#xff1a; data cache.load(id);//从缓存加载数据 If(data null){ data db.load(id);//从数据库加载数据 cache.put(id,data);//保存到 cache 中 } return data;在我们的单体项目中可以用Map作…

如何使用GCC手动编译stm32程序

如何不使用任何IDE&#xff08;集成开发环境&#xff09;编译stm32程序? 集成开发环境将编辑器、编译器、链接器、调试器等开发工具集成在一个统一的软件中&#xff0c;使得开发人员可以更加简单、高效地完成软件开发过程。如果我们不使用KEIL,IAR等集成开发环境&#xff0c;…

一个专为云原生环境设计的高性能分布式文件系统

大家好&#xff0c;今天给大家分享一款开源创新的分布式 POSIX 文件系统JuiceFS&#xff0c;旨在解决海量云存储与各类应用平台&#xff08;如大数据、机器学习、人工智能等&#xff09;之间高效对接的问题。 项目介绍 JuiceFS 是一款面向云原生设计的高性能分布式文件系统&am…

Vue-TreeSelect组件最下级隐藏No sub-options

问题&#xff1a;最下级没有数据的话&#xff0c;去除No sub-options信息 为什么没下级&#xff0c;会展示这个&#xff1f; 整个树形结构数据都是由后端构造好返回给前端的。默认子类没数据的话&#xff0c;children是一个空数组。也就是因为这最下级的空数组&#xff0c;导致…

k8s集群增加nfs-subdir-external-provisioner存储类

文章目录 前言一、版本信息二、本机安装nfs组件包三、下载nfs-subdir-external-provisioner配置文件并进行配置1.下载文件2.修改配置 三、进行部署备注&#xff1a;关于镜像无法拉取问题的处理 前言 手里的一台服务器搭建一个单点的k8s集群&#xff0c;然后在本机上使用nfs-su…

C语言数据结构-链表

C语言数据结构-链表 1.单链表1.1概念与结构1.2结点3.2 链表性质1.3链表的打印1.4实现单链表1.4.1 插入1.4.2删除1.4.3查找1.4.4在指定位置之前插入或删除1.4.5在指定位置之后插入或删除1.4.6删除指定位置1.4.7销毁链表 2.链表的分类3.双向链表3.1实现双向链表3.1.1尾插3.1.2头插…

【SpringCloud详细教程】-04-服务容错--Sentinel

精品专题&#xff1a; 01.《C语言从不挂科到高绩点》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482 02. 《SpringBoot详细教程》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12789841.html?spm1001.20…

【Python中while循环】

一、深拷贝、浅拷贝 1、需求 1&#xff09;拷贝原列表产生一个新列表 2&#xff09;想让两个列表完全独立开&#xff08;针对改操作&#xff0c;读的操作不改变&#xff09; 要满足上述的条件&#xff0c;只能使用深拷贝 2、如何拷贝列表 1&#xff09;直接赋值 # 定义一个…

在 Mac(ARM 架构)上安装 JDK 8 环境

文章目录 步骤 1&#xff1a;检查系统版本步骤 2&#xff1a;下载支持 ARM 的 JDK 8步骤 3&#xff1a;安装 JDK步骤 4&#xff1a;配置环境变量步骤 5&#xff1a;验证安装步骤 6&#xff1a;注意事项步骤7&#xff1a;查看Java的安装路径 在 Mac&#xff08;ARM 架构&#xf…

对比C++,Rust在内存安全上做的努力

简介 近年来&#xff0c;越来越多的组织表示&#xff0c;如果新项目在技术选型时需要使用系统级开发语言&#xff0c;那么不要选择使用C/C这种内存不安全的系统语言&#xff0c;推荐使用内存安全的Rust作为替代。 谷歌也声称&#xff0c;Android 的安全漏洞&#xff0c;从 20…

小程序基础:流程。

一、前言 该文章是个人的学习笔记&#xff0c;是学习了黑马程序的微信小程序开发视频后写的笔记&#xff0c;将老师所讲的内容重点汇总起来&#xff0c;目的是为了方便自己日后回顾&#xff0c;同时也方便大家学习和了解小程序的开发 想要入门小程序&#xff0c;那么看这一篇文…

【漏洞复现】CVE-2020-13925

漏洞信息 NVD - CVE-2020-13925 Similar to CVE-2020-1956, Kylin has one more restful API which concatenates the API inputs into OS commands and then executes them on the server; while the reported API misses necessary input validation, which causes the hac…

数据结构 (11)串的基本概念

一、串的定义 1.串是由一个或者多个字符组成的有限序列&#xff0c;一般记为&#xff1a;sa1a2…an&#xff08;n≥0&#xff09;。其中&#xff0c;s是串的名称&#xff0c;用单括号括起来的字符序列是串的值&#xff1b;ai&#xff08;1≤i≤n&#xff09;可以是字母、数字或…

LLM PPT Translator

LLM PPT Translator 引言Github 地址UI PreviewTranslated Result Samples 引言 周末开发了1个PowerPoint文档翻译工具&#xff0c;上传PowerPoint文档&#xff0c;指定想翻译的目标语言&#xff0c;通过LLM的能力将文档翻译成目标语言的文档。 Github 地址 https://github.…

Python数据分析实例五、US 大选捐款数据分析

美国联邦选举委员会 (FEC) 公布了对政治竞选活动的贡献数据。这包括投稿人姓名、职业和雇主、地址和投款金额。2012 年美国总统大选的贡献数据以单个 150 MB 的 CSV 文件P00000001-ALL.csv形式提供,该文件可以通过以下pandas.read_csv加载: import pandas as pdfec = pd.r…

3.http模块

文章目录 [TOC](文章目录) 1、什么是http模块&#xff1f;1.1.作用1.2.服务器相关概念1.2.创建基本的web服务器-实现的核心步骤和代码1.2.1导入http模块1.2.2.req 请求对象 1.3.根据不同的url地址 响应不同的html内容1.4.案例-clock时钟的web服务器 1、什么是http模块&#xff…

【Nginx】核心概念与安装配置解释

文章目录 1. 概述2. 核心概念2.1.Http服务器2.2.反向代理2.3. 负载均衡 3. 安装与配置3.1.安装3.2.配置文件解释3.2.1.全局配置块3.2.2.HTTP 配置块3.2.3.Server 块3.2.4.Location 块3.2.5.upstream3.2.6. mine.type文件 3.3.多虚拟主机配置 4. 总结 1. 概述 Nginx是我们常用的…

uniapp开发微信小程序笔记8-uniapp使用vant框架

前言&#xff1a;其实用uni-app开发微信小程序的首选不应该是vant&#xff0c;因为vant没有专门给uni-app设置专栏&#xff0c;可以看到目前Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本&#xff0c;并由社区团队维护 React 版本和支付宝小程序版本。 但是我之前维…

IDEA2024创建一个spingboot项目

以下是创建一个基本的 Spring Boot 项目的步骤和示例&#xff1a; 初始化一个springboot工程其实有许多方法&#xff0c;笔者这里挑了一个最快捷的方式搭建一个项目。我们直接通过官方平台&#xff08;start.spring.io&#xff09;进行配置&#xff0c;然后下载压缩包就可以获取…

Easyexcel(7-自定义样式)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09;Easyexcel&#xff08;5-自定义列宽&#xff09;Easyexcel&#xff08;6-单…