JVM学习小结

引入:类的加载过程:

加载——链接(校验,准备,解析)——初始化——卸载

*类加载的任务:1、是获取二进制字节流;

              2、是将字节流代表的静态存储结构转化为方法区的运行时数据结构;

              3、在java堆中生成class对象,作为方法区的数据访问入口。

*链接:将加载完成的class合并到jvm运行时状态中

     **校验:文件格式验证;元数据验证;字节码验证;符号引用验证

    **准备:准备类中定义的字段,方法和接口等所必需的数据结构

    **解析:装入类所引用的其他类,虚拟机将常量池中的符号引用替换为直接引用

*初始化:初始类变量和其他资源

~初始化的四种情况:1、遇到new,getStatic,putStatic、invokeStatic;

                                   2、使用java.lang.reflect包中的方法对类进行反射调用时;

                                   3、对其父类未进行初始化,需要先对它的父类进行初始化;

                                  4、虚拟机启动会初始化一个主类(main)

*卸载:即回收,无引用的对象

~无引用情况:1、该类的所有实例都已经被GC,即jvm中已经不存在该class的实例

                       2、加载该类的ClassLoader已经被GC;

                       3、该类的Class对象没有被任何地方引用,即不能通过任何反射访问该类的方法

java虚拟机主要有三个部分:

一、类加载机制

二、运行时数据区

三、执行引擎

四、直接内存

一、类加载机制

将写好的.java文件编译生成二进制的字节码.class文件,然后将.class文件加载进虚拟机,

*装载主要内容:1、是获取二进制字节流;

                           2、是将字节流代表的静态存储结构转化为方法区的运行时数据结构;

                          3、在java堆中生成class对象,作为方法区的数据访问入口。

*类加载器有:1、虚拟机自带的加载器;2、自己编写的加载器

        **虚拟机自带的加载器有:

        (1)启动类加载器;<c++编写的>:读取java核心类库JRE/lib//rt.jar

        (2)扩展类加载器;<java编写的>:读取java平台扩展功能的jar包java_Home

        (3)应用程序类加载器<java编写的>:记载classpath中指定的jar包及目录中的class

     **用户自定义的加载器:继承java.lang.classloader

     **加载过程中采用双亲委派机制:即先交给父类加载器实现(为了保证java健壮性和安全性)

二、运行时数据区

再将类加载完成后,进入链接阶段,把二进制数据合并到JRE中

    *运行时数据区分为五个部分:指令寄存器,java栈,堆,方法区,本地方法栈

        **程序计数器:为每个线程私有的,指向当前线程执行的程序语句,是java虚拟机唯一没有规定OutOfMemoryError的区域(如果线程执行的是一个java方法,计数器记录的是虚拟机字节码指令的地址;如果线程执行的是native方法,则计数器指令为空)

!为什么每个线程都需要程序计数器:是因为jvm多线程线程的是通过线程切换实现的,为了保证线程切换时能够恢复到正确的位置

        **java栈:每个线程私有的,栈是由一个个的栈帧组成,每个方法对应一个栈帧,当前执行的方法位于栈顶。每个栈帧中包含有:局部变量表(基本数据、对象引用、返回地址)、操作数栈、动态链接、方法出入口。栈是运行时单位,解决程序如何执行问题

虚拟机规定了两种异常;1、请求栈的深度大于虚拟机所允许的深度,这时会抛出StackOverFlowError;2、如果java虚拟机运行动态扩展虚拟机栈时,当扩展的时候没有办法分配到内存的时候就会报OutOfMemoryError

        **堆:为线程共享的,非安全的。主要存储的是对象本身和数组,他们的引用存储于栈

内存回收主要是针对堆进行的,java8之前,运行时常量池位于永久代,永久区保存在堆里;java8之后,将永久代从堆中移除,用元空间替换掉了永久代(元空间存储于本地内存,避免了永久代内存溢出问题和不利于调优),并将运行时常量池存储于方法区。

异常:当堆中没有内存完成实例分配,并且无法扩展时,就会抛出OutOfMemoryError

        **方法区:为线程共享的,(称之为“非堆”)存储的是每个类的信息(即元结构,包括类的名称、方法信息。字段信息、静态变量(静态方法,成员方法)、常量、以及编译器编译后的代码)

异常:当方法区中无法满足内存分布时就会抛出OutOfMemoryError

               ***运行时常量区:是每个类和接口的常量池的运行时表现形式

        **本地方法栈:与java栈类似,Java栈是为java方法服务,本地方法栈是为本地方法服务的(存储每个native方法的调用状态)

对象访问的方式:(1)句柄访问(2)直接指针访问(HotSpot采用此种方式)

三、执行引擎

        分配给运行时方法区的字节将由执行引擎执行,执行引擎读取字节码并逐段执行

        组成部分:解释器、JIT编译器(即时编译器)、垃圾回收器

        *解释器:一个方法被调用多次,每次都需要重新解释(执行速度慢)

        *编译器:编译成本机代码(直接用于方法重复调用)

        *垃圾回收器:收回并删除未引用的对象

Note:java之所以是跨平台语言,与他的一次编译,多次运行有关也和java虚拟机有关

java本地接口(JNI):与本地方法库进行交互并提供执行引擎所需的本地库

本地方法库:是一个执行引擎所需的本地库的集合

四、直接内存

    直接内存是在内存中直接分配出的一部分,不是虚拟机运行时数据区的部分,可以直接对内存进行操作

异常:当内存空间无法动态扩展时就会出现OutOfMemoryError

垃圾回收:(进行GC的前提是线程到达安全点,即状态不在发生变化)

运行线程会到达安全点(safe point)停顿下来进行GC,采用中断操作挂起

处于sleep和Block状态的线程需要到达安全域(Safe Region)

垃圾回收机制概述:JVM将堆划分为三个层次,新生代、老年代、永久代,新生代中有划分为三个部分(伊甸区,幸存区0,幸存区1(8:1:1),其中幸存区一个为from区,一个为to区),当一个对象被创建首先会在伊甸区被创建,当伊甸区满时,会触发Minor GC的时候,根据可达性算法,判断对象是否消亡,没有消亡的对象就会存储到其中一个幸存区,称之为from区,消亡的则会被Minor GC kill。然后继续在伊甸区创建对象,进入survivor区的对象也不是安全的,再一次Minor GC时,还会检查Enden和Survivor存放的对象是否存活,并将存活的对象转移至另外一个幸存区,称之为to区,所以from区和to区是可以灵活转化的,两个Survivor区切换好几次以后就会进入老年代(存活了足够长的时间,由GC 阈值 决定,默认值为15,对象的GC年龄会随着清理次数而累加),进入老年代也不一定安全,当老年代存储空间不足时,会进行Full GC操作,依然可能被kill

Minor GC的触发是在伊甸区满时,Full GC的触发是在老年代满时

何时开始GC?当堆中内存不足时

(即:伊甸区和幸存区存活足够长时间的对象,向老年代转移,老年代中也无空间存储)

GC是针对什么东西?当前不可达对象(即从GC Roots出发,经过一次标记清理之后仍然没有复活的对象)

GC主要做什么?新生代:复制清理(主要是Minor GC,轻量级)

         老年代:标记清楚和标记整理算法(Full GC)

             永久代:存放java类和加载类的加载器本身

垃圾回收算法:(1)标记-清楚算法;(2)复制算法(3)标记整理算法

如何判断对象是否存活?(1)引用计数法;(2)可达性分析

(1)引用计数法:在对象上添加一个引用计数器,每当有一个对象引用时计数器加一,当时用完对象时,计数器减一,若计数器值为零,则表示不被使用

(2)可达性分析:从GC Roots作为起点,从这些结点向下搜索,搜索路径称为引用链

GC Roots的选取:(1)本地变量表中引用的对象(2)方法区中静态变量引用的对象;

               (3)方法去中常量引用的对象(4)native方法引用的对象

无引用情况:1、该类的所有实例都已经被GC,即jvm中已经不存在该class的实例

                     2、加载该类的ClassLoader已经被GC;

                     3、该类的Class对象没有被任何地方引用,即不能通过任何反射访问该类的方法

如何快速枚举GC Roots?使用Oop Map数据结构进行实现

引用的分类:强引用、软引用、弱引用、虚引用

有七种不同的垃圾回收器:

(1)serial(串行GC):Client模式下,单线程基于复制算法的新生代收集器

(2)parnew(并行GC):serial的多线程版

(3)paraller scavenge(并行GC):多线程基于复制算法的新生代收集器

(4)Serial Old(串行GC):Client模式下,单线程基于标记整理算法的老年代回收器

(5)paraller old(并行GC):多线程基于标记整理算法的老年代回收器,在注重吞吐量以及CPU敏感的场合,可以优先考虑Paraller old和paraller scavenge的收集器组合

(6)CMS(并发GC):是一种以获取最短回收停顿时间为目标的收集器,工作在老年代,基于标记-清除算法实现的

(7)G1收集器:是JDK1.7提供的一个工作在新生代和老年代的收集器,基于标记-整理算法实现

System.gc()讲解:https://blog.csdn.net/yewei02538/article/details/52386642

Finalize()函数:https://blog.csdn.net/duchao123duchao/article/details/45131199

猜你喜欢

转载自blog.csdn.net/sinat_36722750/article/details/81838270