深入理解JAVA虚拟机-笔记

一、JVM

  是整个Java平台的基石,是Java技术用于实现硬件与操作系统无关的关键部分,是保证用户机器免于恶意代码损害的屏障。

  可以被看做是一台抽象的计算机。 有⾃己的指令集和运行时的内存区域。

  与Java语⾔言并没有必然的联系。

    只有特定的二进制文件格式-Class文件格式关联。

    毕竟虚拟机其实只是一个程序,比我们写的hello world牛点。

二、JVM的运⾏时内存区域划分

  语⾔言级别内存划分。

page2image1682480page2image3684784page2image1622368page2image3679168page2image3678752page2image3693936page2image3677712page2image3697888page2image3697680

1. 线程私有

1.1. 程序计数器-pc 寄存器

  每个jvm线程都有⾃己的pc 计数器

  线程执⾏到的字节码的行号指示器,只要不是native方法, ⽤于执行过程中的循环、跳转、分⽀支、异常处理理线程恢复等。

  ⽣命周期与线程相同

1.2. 虚拟机栈- stack

  描述的是⽅法执行的内存模型,⽅法的执行过程就是虚拟机栈的入栈与出栈

扫描二维码关注公众号,回复: 1097031 查看本文章

  用于存储局部变量和部分过程结果(些尚未算好的结果)的数据结构。

  也被用来处理动态链接、方法返回值和异常分派。

  生命周期与JVM线程相同,⽅法执⾏时都会创建⼀个栈帧。

  随着⽅法调⽤而创建,随着方法结束(⽆论正常还是异常完成)而销毁。

  局部变量表和操作数栈都是在编译期确定,在方法的code属性中。

  1.2.1. 局部变量表

    存放在编译时已经确定的8种基本类型、对象引用等。空间⼤小是确定的,

    在运行期间不会改变。

    ⽅法参数和局部变量

    局部变量 没有 初始化阶段,即不会被赋零值。

  1.2.2.操作数栈

    类似于数据寄存器
    方法开始执行时是空的, 运算过程中会有出栈入栈操作。

1.3. 本地方法栈⽤

  用来⽀持native⽅法执⾏

  native关键字说明其修的⽅法是一个原⽣态方法,方法对应的实现不是在当前文件,⽽是在⽤其他语⾔(如C和C++)实现的文件中

2. 线程共享

  2.1. 方法区

    是堆的一个逻辑部分 虚拟机启动时创建,1.8 已经开始直接使⽤用本地内存,元 空间。

    存储虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。 类的 版本信息等 字段 方法 接口等。 常量池。- 运⾏行行时常量池。 类、实例例、接口初始化时⽤用 到的特殊方法。

    不严谨的说,包含整个程序永远唯一的元素。

  2.2. Java 堆 -heap

    可供各个线程共享的运行时内存区域。

    最⼤的⼀块 ⼤小可以是固定的,也可以是动态的。 虚拟机启动时创建 几乎所有对象与数组都在堆上分配。

    可能会划分出多个线程私有的分配缓冲区 TLAB

  2.3 直接内存

    虚拟机规范外的内存区域,如NIO直接使⽤用的堆外内存。

 

三、内存回收特殊的内存模块-不需回收或回收效率低

    线程私有的的内存:程序计数器、虚拟机栈、本地方法栈,随着线程生灭,分 配和回收都是确定的。

    永生代,就是前⾯面说的方法区,回收的效率很低。 现已改为 元空间,直接使⽤用的是本地内存。回收的两个内容为:

    1. 废弃常量 没有任何⼈人⽤用

    2. ⽆用的类 条件比较苛刻

      1. 该类的所有实例都已经被回收。
      2. 加载该类的ClassLoader已经被回收
      3. Class对象没有任何地方被引用,无法在任何地方通过反射访问该类

  1. 堆内存分代——有针对性的采⽤不同的回收机制,有利 于内存回收

    1.1. 年轻代和⽼年代      

      1. 年轻代对象朝生夕灭,

        一般划分是 一个Eden区和两个Survivor区。2. ⽼年代对象历久弥坚

    1.2. 创建对象时的分配

      1. 对象优先分配到Eden区,经历一定次数的回收之后,仍然存活的对象进⼊老年代。

      2. ⼤对象直接进⼊⽼年代

  2. 内存回收

      2.1. GC 分类 - 何时回收

        1. Minor GC 发生在新生代的内存回收

          当jvm无法为一个新的对象分配内存空间时会触发Minor GC,⽐如当Eden区满了,或者内存不连续。

        2. Full GC 发生在⽼年代的回收

          如果⽼年代没有⾜够空间,就会进行一次Full GC 对新生代和⽼年代都进行GC

      2.2. 哪些对象可以回收

        2.2.1. 引⽤用计数算法

          为对象添加引⽤用计数器,每个引⽤用计数+1,引⽤用失效,计数-1.会有循环引⽤用.

        2.2.2. 可达性分析

          通过一系列列的 GC Roots 对象作为起始点,搜索所⾛走过的路路径称为引⽤用链。

          当一个对象没被引⽤用的时候,就判定为可回收对象。

            GC Roots:

              1. 虚拟机栈中引⽤用的对象
              2. 方法区中类静态属性引⽤用的对象

              3. 方法区中常量引⽤用的对象
              4. 本地方法栈中引⽤用的对象

  3. 如何回收 - 回收算法介绍

    3.1 年年轻代回收算法

        3.1.1 标记-清除

          标记出所有需要回收的对象

          统一回收所有被标记的对象

          不⾜:

            效率,标记和回收的效率都不高

            空间,会产生大量的离散的内存碎片


        3.1.2 复制  

          空间换效率 新生代基本都采⽤用这种算法。

          将还存活的对象复制到另一块内存上,其他的一次性清理掉。Eden和2 个 Survivor

          HotSpot 默认是 8:1:1
          如果 10% 不够放置存活的对象,则直接进入老年代。


    3.2 ⽼年代算法

      3.2.1 标记-整理

        ⽼年代,一般就是对象存活率比较高。 ⽼而弥坚。

        与标记清理类似,但是不清理,而是让存活的对象移动到一端,

猜你喜欢

转载自www.cnblogs.com/liuguobin/p/JVM.html