我对JVM的认知总结[笔记]

我对JVM的认知总结[笔记]

JVM是可运行Java代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、
一个垃圾回收,堆 和 一个存储方法域。
JVM 是运行在操作系统之上的,它与硬件没有直接
的交互

JVM的运行过程

JAVA源文件->编译器->class字节码->JVM->机器码

java虚拟机的多平台运行

每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这也就是 Java 为什么能够
跨平台的原因了 ,当一个程序从开始运行,这时虚拟机就开始实例化了,多个程序启动就会
存在多个虚拟机实例。程序退出或者关闭,则虚拟机实例消亡,多个虚拟机实例之间数据不
能共享

线程是一个什么东东

线程指程序执行过程中的一个线程实体。JVM 允许一个应用并发执行多个线程。
Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的映射关系。当线程本地存储、缓
冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程

Java 线程结束,原生线程随之被回收。操作系统负责调度所有线程,并把它们分配到任何可
用的 CPU 上。当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。当线程结束时,会释放原生线程和 Java 线程的所有资源。

Hotspot JVM 后台运行的系统线程主要有下面几个:

线程 描述
虚拟机线程 (VM thread)这个线程等待 JVM 到达安全点操作出现。这些操作必须要在独立的线程里执行,因为当堆修改无法进行时,线程都需要 JVM 位于安全点。这些操作的类型有:stop-the-world 垃圾回收、线程栈 dump、线程暂停、线程偏向锁(biased locking)解除。
GC 线程 这些线程支持 JVM 中不同的垃圾回收活动
编译器线程 这些线程在运行时将字节码动态编译成本地平台相关的机器码。
信号分发线程 这个线程接收发送到 JVM 的信号并调用适当的 JVM 方法处理。

JVM的基础总结

我对JVM的认知总结[笔记]

JVM的内存区域

我对JVM的认知总结[笔记]

  • JVM 内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区
    域【JAVA 堆、方法区】、直接内存
  • 线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束 而 创建/销毁(在 Hotspot
    VM 内, 每个线程都与操作系统的本地线程直接映射, 因此这部分内存区域的存/否跟随本地线程的
    生/死对应)
  • 线程共享区域随虚拟机的启动/关闭而创建/销毁
  • 直接内存并不是 JVM 运行时数据区的一部分, 但也会被频繁的使用: 在 JDK 1.4 引入的 NIO 提
    供了基于 Channel 与 Buffer 的 IO 方式, 它可以使用 Native 函数库直接分配堆外内存, 然后使用
    DirectByteBuffer 对象作为这块内存的引用进行操作(详见: Java I/O 扩展), 这样就避免了在 Java
    堆和 Native 堆中来回复制数据, 因此在一些场景中可以显著提高性能

JVM的模型

我对JVM的认知总结[笔记]

jvm运行时内存

我对JVM的认知总结[笔记]

  • 新生代

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

  1. Eden区

    Java新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老
    年代)。当Eden区内存不够的时候就会触发MinorGC,对新生代区进行
    一次垃圾回收

  2. ServivorFrom

    上一次 GC 的幸存者,作为这一次 GC 的被扫描者

  3. ServivorTo

    保留了一次 MinorGC 过程中的幸存者(上一次 GC 的幸存者,作为这一次 GC 的被扫描者)

  • 老年代

主要存放应用程序中生命周期长的内存对象

老年代的对象比较稳定,所以 MajorGC 不会频繁执行。在进行 MajorGC 前一般都先进行
了一次 MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足
够大的连续空间分配给新创建的较大对象时也会提前触发一次 MajorGC 进行垃圾回收腾出空间

  • 永久代

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

  1. 新特性1.8

    在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间
    的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用
    本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入 native
    memory, 字符串池和类的静态变量放入 java 堆中,这样可以加载多少类的元数据就不再由
    MaxPermSize 控制, 而由系统的实际可用空间来控制


  • 延伸
  1. MinorGC【 采用复制算法】

    MinorGC 的过程(复制->清空->互换)
    from区与to区的角色互换(上一次 GC 的幸存者,作为这一次 GC 的被扫描者)
    1 : eden 、 servicorFrom 复制到 ServicorTo,年龄+1
    首先,把 Eden和 ServivorFrom区域中存活的对象复制到 ServicorTo区域(如果有对象的年
    龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如果 ServicorTo 不
    够位置了就放到老年区);

    2 : 清空 eden 、 servicorFrom
    然后,清空 Eden 和 ServicorFrom 中的对象;

    3 : ServicorTo 和 ServicorFrom 互换
    最后,ServicorTo 和 ServicorFrom 互换,原 ServicorTo 成为下一次 GC 时的 ServicorFrom区

  2. MajorGC【采用标记清除算法】

    首先扫描一次所有老年代,标记出存活的对象,然后回收没
    有标记的对象。MajorGC 的耗时比较长,因为要扫描再回收。MajorGC 会产生内存碎片,为了减
    少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。当老年代也满了装不下的
    时候,就会抛出 OOM(Out of Memory)异常


JVM垃圾回收机制的演变

我对JVM的认知总结[笔记]
我对JVM的认知总结[笔记]
我对JVM的认知总结[笔记]