JVM笔记

一、什么是JVM:

  • Java虚拟机是一台执行Java字节码的虚拟计算机,它拥有独立的运行机制,其运行的Java字节码也未必是由Java语言编译而成。

二、JVM的作用:

  • Java虚拟机就是二进制字节码的运行环境,负责装载字节码到其内部,解释编译为对应平台的机器执行指令,每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作,怎么处理操作,处理结果放在那里。

三、JVM的特点:

  • 一次编译,导出运行
  • 自动内存管理
  • 自动垃圾回收功能

四、JVM种类:

  • Sun Classic VM:世界上第一框商用Java虚拟机JDK1.4时被完全淘汰。
  • Exact VM:JDK1.2时Sun公司提供该虚拟机,后被HotSpot虚拟机替换。
  • JRockit VM:该虚拟机号称是世界上最快的JVM,因为其内部不包含解释器,所以速度确实快,2008年,开发该虚拟机的公司呗Oracle公司收购。
  • J9 VM:IBM公司研发,广泛适用于IBM公司的各种Java产品。
  • HotSpot VM:目前HotSpot虚拟机占有绝对的市场地位,不管是曾经大量使用的JDK6还是现在使用较多的JDK8中默认的虚拟机都是HotSpot,Sun JDK和Open JDK的默认虚拟机都是HotSpot。

五、JVM的整体结构:
JVM结构图
1.程序计数器(Program Counter Register):

  • 介绍:它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。

  • 作用:PC寄存器用来存储指向下一条指令的地址,也即将要执行的指令代码,由执行引擎读取下一条指令。

2.Java虚拟机栈(Java stack):

  • 介绍:Java虚拟机栈(Java Virtual Machine Stack),早期也叫Java栈,每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次的Java 方法调用。(线程私有)。

  • 作用:主管Java程序的运行,它保存方法的局部变量(8种基本数据类型,对象的引 用地址)、部分结果、并参与方法的调用和返回。

  • 栈的特点:栈是一种快速有效的分配内存的方式,访问速度仅次于程序计数器。Java直接对栈的操作只有两个:每个方法的执行,伴随着进栈(入栈、压栈)、执行结束后的出栈工作。栈中不存在垃圾回收问题。

  • 栈中存储的栈帧的内部结构:

  • 局部变量表(Local Variables)

  • 操作数栈(Operand Stack)(或表达式)

  • 动态链接(Dynamic Linking)(或指向运行时常量池的方法引用)

  • 方法返回值地址(Return Address)(或方法正常退出或者异常退出的定义)

  • 一些附加信息
    Java栈帧结构

3.本地方法栈

  • Java虚拟机用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用。
    本地方法栈也是线程私有的,它由C语言实现
    本地方法栈的具体实现是Native Method Stack中登记native方法,在Execution Engine执行加载本地方法库。

4.堆

  • 一个Java实例只存在一个堆内存,堆也是唯一Java内存管理的核心区域。
  • Java堆区在JVM启动的时候即被创建,其空间大小也就确定了,是JVM管理中的最大一块内存空间(堆的大小是可以调节的)。
  • 《Java虚拟机规范》规定,堆可以处于物理上不连续的内存空间中,但在逻辑上它应该是被视为连续的。
  • 所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer ,TLAB)。
  • 数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置。
  • 在方法区结束后,堆中的对象不会马上移除,仅仅在垃圾收集的时候才会被移除。
  • 堆是GC(Carbage Collection。垃圾收集器)执行垃圾回收的重点区域
    类的实例化原理
  • 堆内存细分:新生区(Eden+Survivor1+Survivor2)+养老区+元空间(JDK7之前叫做永久区)
    堆空间结构

5.垃圾回收(GC):

  • JVM在进行GC时,并非每次都对三个内存(新生代、老年代、方法区)区域一起回收,大部分时候回收的都是新生代。
    针对HotSpot VM的实现,它里面GC按照回收区域又分为两大种类型:一种是部分收集(Partial GC),一种是整堆收集(Full GC)
  • 部分收集:不是完整的收集整个Java堆的垃圾收集,其中又分为:
  • 新生代收集(Minor GC / Young GC):只是新生代的垃圾收集。
  • 老年代收集(MaJor GC / Old GC): 只是老年代的垃圾收集。
  • 目前只有CMS GC 会有单独收集老年代的行为
  • 注意:很多时候Major GC 和 Full GC混淆使用,需要具体分辨是老年代回收还是整体回收。
  • 混合回收(Mixed GC):收集整个新生代以及部分老年代的垃圾收集(只有G1 GC会有这种行为)
  • 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。
  • 年轻代GC(Minor GC)触发机制:
  • 当年轻代空间不足时,就会触发Minor GC,这里的年轻代满指的是Eden满,Survivor满不会引发GC(每次Minor GC会清理年轻代的内存)
  • 因为Java对象大多是具备朝生夕死的特性,所以Minor GC非常频繁,一般回收速度也是比较快,这一定义即清晰又易于理解。
  • Minor GC会引发STW,暂停其它用户的线程,等垃圾回收结束,用户线程才会恢复运行。
  • 老年代GC(Major GC / Full GC)触发机制:
  • 指发生在老年代的GC,对象从老年代消失时,我们称为"Major GC" 或 "Full GC"发生了。
  • 出现了Major GC经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scevenge收集器的手机策略里就有直接进行Major GC的策略选择过程。就是说在老年代空间不足时,会先尝试触发Minor GC,如果之后空间还不足,则会触发Major GC)。
  • Major GC的速度一般会比Minor GC慢10倍以上,STW的时间更长。
  • 如果Major GC后,内存还是不足,就报OOM了。
  • Major GC的速度一般会比Minor GC慢10倍以上。
  • Full GC触发机制
  • 1、调用System.gc()时,系统建议执行Full GC,但是不必然执行。
  • 2、老年代空间不足。
  • 3、方法区空间不足。
  • 4、通过Minor GC后进入老年代的平均大小大于老年代的可用内存。
  • 5、由Eden区、survivor space0(From Space)区向survivor space1(To Space)取复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象的大小。
  • 说明:Full GC是开发或调优中尽量要避免的,这样暂停时间(STW)会短一些。

6.方法区

  • 方法区可以看做是一块独立于Java堆的内存结构。
  • 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。
  • 方法区在JVM启动的时候被创建,并且它的实际物理内存空间中和Java堆区一样都可以是不连续的。
  • 方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。
  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误。
  • 关闭JVM就会释放这个区域的内存。
  • 方法区的垃圾收集主要是回收两部分内容,常量池中废弃的常量和不再使用的类型。

7.执行引擎

  • 执行引擎的任务就是将字节码指令解释/编译为对应平台上的本地机器指令,简单来说,JVM中的执行引擎充当了将高级语言翻译为机器语言的译者。