美文网首页
Java虚拟机

Java虚拟机

作者: 小张同学_loveZY | 来源:发表于2018-08-27 14:07 被阅读0次

    java官网介绍了虚拟机的一些概况,建议开始的时候先浏览一遍,淡然JVM 官方介绍

    这本文档内容比较多,建议后面有时间再认真学习JVM SE 8 文档

    另外就是建议我入门用的《深入理解java虚拟机 第二版》

    JVM工作原理

    JVM主要分为类加载器、执行引擎、运行时数据区域。

    运行数据区分为五个部分: 方法区、堆、栈、程序计数器、本地方法栈。

    • 线程共享:方法区、Java堆;
    • 线程私有:Java栈、本地方法栈、程序计数器;

    每个线程都有自己独立的栈空间和程序计数器。

    JIT即时编译 --- 加速

    just-in-time(JIT):
    为了提高热点代码的执行效率,在运行时虚拟机将会把热点代码编译成与本地平台相关的机器码。

    热点代码:
    • 被多次调用的方法。
    • 被多次调用的循环体

    main 函数运行将会创建一个JVM实例

    经历过程:
    1. 根据系统环境变量,创建装载JVM的环境与配置;

    2. 寻找JRE目录,寻找jvm.dll,并装载jvm.dll;

    3. 根据JVM的参数配置,如:内存参数,初始化jvm实例;

    4. JVM实例产生一个引导类加载器实例(Bootstrap Loader),加载Java核心库,然后引导类加载器自动加载扩展类加载器(Extended Loader,加载Java扩展库,最后扩展类加载器自动加载系统类加载器(AppClass Loader),加载当前的Java类;类加载器采用双亲委派机制

    1. 当前Java类加载至内存后,会经过 验证、准备、解析 三步,将Java类中的 类型信息、属性信息、常量池 存放在方法区内存中,方法指令直接保存到栈内存中,如:main函数;

    2. 执行引擎开始执行栈内存中指令,由于main函数是静态方法,所以不需要传入实例,在类加载完毕之后,直接执行main方法指令;

    3. main函数执行主线程结束,随之守护线程销毁,最后JVM实例被销毁;

    启动类加载的情况
    1. 创建类的实例:使用new关键字实例化对象;
    2. 访问类的静态变量,(不包括被final修饰的静态变量);
    3. 访问类的静态方法;
    4. 使用java.lang.reflect进行反射调用;
    5. 子类初始化时,会先初始化父类;
    双亲委派机制:如果一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类,而是把这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。可以保证不同机器下类的一致性。

    JVM内存分配策略

    JVM内存内存分为五个部分: 方法区、堆、栈、程序计数器、本地方法栈。

    程序计数器:

    线程私有,记录线程所执行的虚拟机字节码指令的地址;如果正在执行的是native方法,这个计数值则为空。唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

    Java虚拟机栈:

    线程私有,描述Java方法执行的内存模型。如果线程请求栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常;如果虚拟机栈动态扩展时无法申请到足够的内存,抛出 OutOfMemoryError异常。

    本地方法栈:

    线程私有,描述native方法执行的内存模型。有的虚拟机(如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。

    Java堆:

    线程共享,存放对象实例及数组,是垃圾收集器管理的主要区域,采用分代收集策略,所以Java堆会细分为新生代和老年代。根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上连续的即可。如果堆中没有内存完成实例分配,并且堆也无法再扩展时,抛出OutOfMemoryError异常。

    方法区:

    线程共享,存储已被虚拟机加载的类信息、常量池、静态变量、即时编译器编译后的代码等数据。如果方法区无法满足内存分配需求,抛出OutOfMemoryError异常。

    JVM堆一般又可以分为以下三部分:新生代、老年代、永久代;

    GC(garbage collection)

    判断一个对象是否是垃圾的算法:
    1. 引用计数算法

      • 优点:实现简单、效率高;
      • 缺点:很难解决对象之间相互引用问题;
    2. 可达性分析算法

    可作为GC Roots的对象包括:

    • 虚拟机栈中引用的对象;
    • 本地方法栈中引用的对象;
    • 方法区中类静态属性引用的对象;
    • 方法区中常量引用的对象;

    可达性分析必须在一个能确保一致性的快照中进行,一致性是指在整个分析过程中整个执行系统必须冻结,不可以出现分析过程中对象引用关系还在不断变化的情况,该点不满足的话可达性分析结果不准确。所以这点是导致GC进行时必须停顿所有线程的原因。

    四种引用:

    • 强引用:只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
    • 软引用:对软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。
    • 弱引用:对弱引用关联着的对象,只能生存到下一次垃圾收集发生之前。
    • 虚引用:对象是否有虚引用,完全不会对其生存时间构成影响,也无法通过虚引用来取得对象实例。关联虚引用唯一目的就是能在对象被收集器回收时收到系统通知。
    finalize()方法

    应尽量避免使用它,甚至可以忘掉它

    其执行的时间不确定,甚至是否被执行也不确定(Java程序的不正常退出时),而且运行代价高昂,无法保证各个对象的调用顺序(甚至有不同线程中调用);如果需要"释放资源",可以定义显式的终止方法,并在"try-catch-finally"的finally{}块中保证及时调用;

    JVM如何进行对象标记
    1. 第一次标记:在可达性分析后发现到GC Roots没有任何引用链相连时,被第一次标记;并且进行一次筛选:此对象是否必要执行finalize()方法;没有必要执行的情况,则标记对象已死;有必要执行的情况,则对象被放入F-Queue队列中;

    2. 第二次标记:GC将对F-Queue队列中的对象进行第二次小规模标记;finalize()方法是对象逃脱死亡的最后一次机会;一个对象的finalize()方法只会被系统自动调用一次,经过finalize()方法逃脱死亡的对象,第二次不会再调用;

    JVM垃圾回收策略

    总的策略是分代收集。

    1. 标记-清除算法【适用于老年代】

    缺点:效率问题:标记、清除两个过程效率都低;空间问题:标记清除之后产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中,需要分配大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

    2. 标记-整理算法【适用于老年代】

    标记过程与“标记-清除”算法一样,唯一区别是在后续步骤不是直接对内存进行清除,而是先让所有活着的对象都向一端移动,然后直接清除掉端边界以外的内存。

    3. 复制算法【空间换时间,适用于对象存活率低的新生代】

    将内存分为两块区域,结合标记-整理算法,但是每次在两个区域交替使用内存。优点:实现简单、效率高、无内存碎片;缺点:内存使用率低,太浪费。

    HotSpot虚拟机的复制算法
    • 将新生代内存分为一块较大的Eden空间和两块较小的Survivor空间;
    • 每次使用Eden和其中一块Survivor;
    • 当回收时,将Eden和使用中的Survivor中还存活的对象一次性复制到另外一块Survivor;
    • 而后清理掉Eden和使用过的Survivor空间;
    • 后面就使用Eden和复制到的那一块Survivor空间,重复步骤3;
    默认Eden:Survivor=8:1,即每次可以使用90%的空间,只有一块Survivor的空间被浪费;
    回收方法区(永久代)

    永久代的垃圾收集主要回收两方面: 废弃常量和无用的类;

    • 废弃常量:判断常量池的对象是否还存在任何引用;
    • 无用的类:(1)该类的所有实例都被回收;(2)该类的ClassLoader已被回收;(3)该类的Class对象没有任何引用;
    对象进入老年代
    1. 大对象:通过参数 -XX:PretenureSizeThreshold=3145287,令大于这个设置值的对象直接在老年代分配。以避免大对象在新生代分配,从而触发新生代GC。

    2. 多次GC仍存活的对象:当对象年龄增加到一定程度(默认15岁,即15次GC未被回收),就会晋升到老年代中。对象晋升老年代的年龄阀值,可以通过参数-XX:MaxTenurigThreshold设置。

    3. 新生代空间提前使用完的时候,较大的对象提前进入老年代。

    相关文章

      网友评论

          本文标题:Java虚拟机

          本文链接:https://www.haomeiwen.com/subject/sllqiftx.html