Java 虚拟机详解

Java 虚拟机详解

  • 1. Java 虚拟机
    • 1.1 什么是虚拟机
    • 1.2 JVM 由哪些部分组成
  • 2. JVM 内存结构
    • 2.1 程序计数器(线程私有)
    • 2.2 虚拟机栈(线程私有)
    • 2.3 本地方法区(线程私有)
    • 2.4 堆(Heap – 线程共享)- 运行时数据区
      • 2.4.1 新生代
        • 2.4.1.1 Eden 区
        • 2.4.1.2 ServivorFrom
        • 2.4.1.3 ServivorTo
        • 2.4.1.4 为什么需要 Survivor
        • 2.4.1.5为什么需要 From 和 To 两个呢
      • 2.4.2 老年代
      • 2.4.3 TLAB
        • 2.4.3.1 什么是 TLAB (Thread Local Allocation Buffer)
        • 2.4.3.2 为什么要有 TLAB
      • 2.4.4 堆是分配对象存储的唯一选择吗
        • 2.4.4.1 逃逸分析
          • 2.4.4.1.1 代码优化之同步省略(消除)
          • 2.4.4.1.2 代码优化之标量替换
          • 2.4.4.1.3 代码优化之栈上分配
          • 2.4.4.1.4 总结
    • 2.5 元数据(线程共享)
      • 2.5.1 静态常量池
      • 2.5.2 运行时常量池
      • 2.5.3 字符串常量池
      • 2.5.4 总结
    • 2.6 直接内存
    • 2.7 OutOfMemoryError(OOM) 内存溢出
      • 2.7.1 Java 堆溢出
      • 2.7.1 虚拟机栈和本地方法栈溢出
      • 2.7.2 运行时常量池溢出
      • 2.7.3 方法区的内存溢出
      • 2.7.4 元数据区的内存溢出
      • 2.7.5 本机直接内存溢出
      • 2.7.6 解决内存溢出
  • 3. 垃圾回收算法
    • 3.1 垃圾回收策略
    • 3.2 垃圾回收发生区域
    • 3.3 如何确定垃圾
      • 3.3.1 引用计数法
      • 3.3.2 可达性分析
      • 3.3.3 不得不说的四种引用
      • 3.3.4 生存还是死亡
    • 3.4. 垃圾回收算法
      • 3.4.1 标记-清除算法(Mark-Sweep)
      • 3.4.2 复制算法(Copying)
      • 3.4.3 标记-整理算法(Mark-Combact)
      • 3.4.4 分代收集算法
        • 3.4.4.1 新生代与复制算法
          • 3.4.4.1.1 新生代GC(MinorGC/YoungGC)
          • 3.4.4.1.2 什么情况下会出现 Young GC
        • 3.4.4.2 老年代与标记整理算法
          • 3.4.4.2.1 老年代GC(MajorGC/FullGC)
          • 3.4.4.2.2 什么情况下回出现 Full GC
        • 3.4.4.3 对象分配规则是什么
        • 3.4.5 分代收集算法的好处
        • 3.4.6 分代收集算法调优原则
      • 3.4.5 分区(增量)收集算法
      • 3.4.6 JVM 相关参数
  • 4. GC 垃圾收集器
    • 4.1 术语
      • 4.1.1 Stop The Word
      • 4.1.2 并行收集 VS 并发收集
      • 4.1.3 吞吐量
      • 4.1.4 安全点
    • 4.2 Serial 垃圾收集器(单线程、复制算法)
    • 4.3 ParNew 垃圾收集器(Serial+多线程)
    • 4.4 Parallel Scavenge 收集器(多线程复制算法、高效)
    • 4.5 Serial Old 收集器(单线程标记整理算法 )
    • 4.6 Parallel Old 收集器(多线程标记整理算法)
    • 4.7 CMS 收集器(多线程标记清除算法)
      • 4.7.1 收集过程
        • 4.7.1.1 初始标记
        • 4.7.1.2 并发标记
        • 4.7.1.3 重新标记
        • 4.7.1.4 并发清除
        • 4.7.1.5 线程重置
      • 4.7.2 CMS 优点
      • 4.7.3 CMS 缺点
      • 4.7.4 CMS 使用场景
    • 4.8 G1 收集器
      • 4.8.1 G1 内存模型
        • 4.8.1.1 G1 堆内存结构
        • 4.8.1.2 G1 堆内存分配
      • 4.8.2 G1 的 GC 模式
        • 4.8.2.1 Young GC 年轻代收集
        • 4.8.2.1 Mixed GC
          • 4.8.2.1.1 Mixed GC 执行过程
            • 4.8.2.1.1.1 初始标记
            • 4.8.2.1.1.2 并发标记
            • 4.8.2.1.1.3 最终标记
            • 4.8.2.1.1.4 筛选回收
        • 4.8.2.2 Full GC
          • 4.8.2.2.1 Full GC 优化原则
      • 4.8.3 G1 的优点
      • 4.8.4 G1 的使用场景
    • 4.9 垃圾收集器总结
    • 4.10 垃圾收集器相关参数

1. Java 虚拟机

1.1 什么是虚拟机

??Java 虚拟机,是一个可以执行 Java 字节码的虚拟机进程。Java 源文件被编译成能被 Java 虚拟机执行的字节码文件( .class )。

??Java 被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java 虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。

??但是,跨平台的是 Java 程序(包括字节码文件),,而不是 JVM。JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 JVM 。

??也就是说,JVM 能够跨计算机体系结构来执行 Java 字节码,主要是由于 JVM 屏蔽了与各个计算机平台相关的软件或者硬件之间的差异,使得与平台相关的耦合统一由 JVM 提供者来实现。

??

1.2 JVM 由哪些部分组成

??JVM 运行内存的分类如上图所示,JVM 内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区域【JAVA 堆、方法区】、直接内存。

??线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束 而 创建/销毁(在 Hotspot VM 内, 每个线程都与操作系统的本地线程直接映射, 因此这部分内存区域的存/否跟随本地线程的 生/死对应)。线程共享区域随虚拟机的启动/关闭而创建/销毁。

??直接内存并不是 JVM 运行时数据区的一部分, 但也会被频繁的使用: 在 JDK 1.4 引入的 NIO 提 供了基于 Channel 与 Buffer 的 IO 方式, 它可以使用 Native 函数库直接分配堆外内存, 然后使用 DirectByteBuffer 对象作为这块内存的引用进行操作(详见: Java I/O 扩展), 这样就避免了在 Java 堆和 Native 堆中来回复制数据, 因此在一些场景中可以显著提高性能。

??

2.1 程序计数器(线程私有)

??程序计数器,Java 线程私有,类似于操作系统里的 PC 计数器,它可以看做是当前线程所执行的字节码的行 指示器:

  • 如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,这个计数器值则为空(Undefined);
  • 此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区

??

2.2 虚拟机栈(线程私有)

??堆即运行时数据区,所有线程共享的一块区域,JVM 垃圾收集器管理的主要区域:

  • 目前主要的垃圾回收算法都是分代收集算法,所以 Java 堆中还可以细分为:新生代和老年代;再细致一点的有 Eden 空间、From Survivor 空间、To Survivor 空间等,默认情况下新生代按照 8:1:1 的比例来分配;
  • 根据 Java 虚拟机规范的规定,Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘一样。

??Java 堆从 GC 的角度还可以细分为: 新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代。

??

2.4.1 新生代

??是用来存放新生的对象。一般占据堆的 1/3 空间。由于频繁创建对象,所以新生代会频繁触发 MinorGC 进行垃圾回收。新生代又分为 Eden 区、ServivorFrom、ServivorTo 三个区。

??
??在 Java8 之前,该块区域为方法区,也叫永久区,指内存的永久保存区域,主要存放 Class 和 Meta(元数据)的信息,Class 在被加载的时候被放入永久区域,它和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的 Class 的增多而胀满,最终抛出 OOM 异常。

??在 Java8 中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:

  • 元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制;
  • 类的元数据放入 native memory, 字符串池和类的静态变量放入 java 堆中, 这样可以加载多少类的元数据就不再由 MaxPermSize 控制, 而由系统的实际可用空间来控制。

??

2.5.1 静态

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年1月20日
下一篇 2021年1月20日

相关推荐