JVM 复习

发布于:2025-09-13 ⋅ 阅读:(13) ⋅ 点赞:(0)

今天来回顾一下JVM的知识点

一、内存区域的划分

1. 程序计数器

  • 作用:每个线程拥有独立的程序计数器,用于记录当前线程执行的字节码行号。在方法执行时,记录下一条指令的地址;如果是Native方法,则值为空。
  • 特点:是JVM中唯一不会发生OutOfMemoryError的区域。
  • 线程安全:线程私有,互不干扰。

2. Java虚拟机栈

  • 作用:存储方法的调用和执行过程,包括局部变量表、操作数栈、动态链接、方法出口等。
  • 生命周期:与线程相同,随线程创建而创建,随线程结束而销毁。
  • 异常:若线程请求的栈深度超过JVM允许的最大深度,抛出StackOverflowError;若栈无法动态扩展,抛出OutOfMemoryError

3. 本地方法栈

  • 作用:为JVM执行Native方法提供服务,类似于虚拟机栈,但服务于非Java语言编写的方法。
  • 实现:不同虚拟机实现方式不同,如HotSpot将本地方法栈与虚拟机栈合二为一。

4. 堆

  • 作用:存放所有对象实例和数组,是垃圾收集器管理的主要区域。
  • 特点:线程共享,所有线程共享堆内存。
  • 分代结构:分为新生代(Eden、Survivor区)和老年代,便于分代垃圾回收。
  • 异常:堆中没有足够空间分配对象实例时,抛出OutOfMemoryError

5. 方法区

  • 作用:存储已被加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等。
  • 实现差异:在HotSpot中,JDK8之前使用永久代实现,JDK8之后改为元空间,使用本地内存。
  • 异常:方法区内存不足时,抛出OutOfMemoryError

二、内存回收算法

1. 引用计数法

  • 原理:每个对象维护一个引用计数器,当引用被添加时计数器加1,引用被移除时减1,计数器为0时回收。
  • 缺点:无法解决循环引用问题,因此未被主流JVM采用。

2. 标记-清除算法

  • 步骤
    1. 标记:从GC Roots开始,标记所有可达对象。
    2. 清除:遍历堆,回收未被标记的对象。
  • 缺点:产生内存碎片,可能导致大对象无法分配。

3. 复制算法

  • 原理:将内存分为两块,每次只使用一块。当一块用完时,将存活对象复制到另一块,然后清空当前块。
  • 优点:无内存碎片,回收效率高。
  • 缺点:内存利用率低,仅适合存活对象少的场景(如新生代)。

4. 标记-整理算法

  • 步骤
    1. 标记:标记所有存活对象。
    2. 整理:将存活对象向一端移动,清理边界外的内存。
  • 优点:无内存碎片,适合老年代。
  • 缺点:移动对象开销较大。

5. 分代收集算法

  • 原理:根据对象生命周期将堆分为新生代和老年代,不同代采用不同回收算法。
    • 新生代:复制算法(存活对象少)。
    • 老年代:标记-清除或标记-整理算法(存活对象多)。
  • 优点:优化垃圾回收效率,减少停顿时间。

三、常见的垃圾收集器

1. Serial收集器

  • 特点:单线程收集,进行垃圾回收时暂停所有用户线程。
  • 适用场景:客户端模式或单核CPU环境。
  • 组合:可与Serial Old收集器搭配使用。

2. ParNew收集器

  • 特点:Serial的多线程版本,回收时暂停所有用户线程。
  • 适用场景:多核环境,常与CMS收集器配合使用。

3. Parallel Scavenge收集器

  • 特点:多线程并行收集,关注吞吐量(运行代码时间/总时间)。
  • 调节:通过-XX:MaxGCPauseMillis-XX:GCTimeRatio参数调整。

4. CMS收集器

  • 特点:并发标记清除,减少停顿时间。
  • 步骤:初始标记、并发标记、重新标记、并发清除。
  • 缺点:产生内存碎片,对CPU资源敏感。

5. G1收集器

  • 特点:面向服务端,将堆划分为多个Region,优先回收价值最大的Region。
  • 优点:可预测停顿时间,适合大内存、多核环境。
  • 目标:替代CMS,成为默认收集器。

6. ZGC和Shenandoah

  • 特点:低延迟,停顿时间控制在毫秒级甚至亚毫秒级。
  • 适用场景:超大内存、对延迟敏感的应用。

四、双亲委派

1. 基本概念

  • 定义:类加载器在加载类时,先委托父类加载器加载,只有父类加载器无法完成时才由自身加载。
  • 目的:避免类的重复加载,保证Java核心API的安全性。

2. 类加载器层次

  • 启动类加载器:加载JDK核心类库(如java.lang.*)。
  • 扩展类加载器:加载扩展目录中的类。
  • 应用程序类加载器:加载用户类路径上的类。

3. 示例

public class ClassLoaderDemo {
    public static void main(String[] args) {
        ClassLoader loader = ClassLoaderDemo.class.getClassLoader();
        System.out.println(loader); // 应用程序类加载器
        System.out.println(loader.getParent()); // 扩展类加载器
        System.out.println(loader.getParent().getParent()); // 启动类加载器(null)
    }
}

五、命令

1. java

  • 作用:启动Java应用程序。
  • 示例
  java -jar app.jar
  java -Xms512m -Xmx1024m MyApp

2. javac

  • 作用:编译Java源代码为字节码。
  • 示例
  javac HelloWorld.java

3. jar

  • 作用:创建和管理JAR文件。
  • 示例
  jar cvf app.jar *.class

4. jps

  • 作用:列出正在运行的Java进程。
  • 示例
  jps -l

5. jstat

  • 作用:监控JVM内存和垃圾回收情况。
  • 示例
  jstat -gc 1234

6. jmap

  • 作用:生成堆转储快照。
  • 示例
  jmap -dump:format=b,file=heap.bin 1234

7. jstack

  • 作用:打印线程堆栈信息,用于分析线程死锁或性能问题。
  • 示例
  jstack 1234 > thread_dump.txt

8. jcmd

  • 作用:多功能诊断命令工具。
  • 示例
  jcmd 1234 GC.class_histogram

9. jconsole和VisualVM

  • 作用:图形化监控工具,提供内存、线程、类加载等实时监控。
  • 启动
  jconsole
  jvisualvm

网站公告

今日签到

点亮在社区的每一天
去签到