JDK体系和JVM架构(内存、垃圾回收、简单的优化)

JDK体系和JVM架构(内存、垃圾回收、简单的优化)

  • 一、JDK、JRE、JVM关系图解
  • 二、JVM虚拟机
    •    1、JVM虚拟机的组成
    •    2、字节码执行引擎
    •    3、运行时数据区(内存模型)
      •      1)堆(heap)
      •      2)栈(stack)
      •      3)程序计数器
      •      4)方法区(元空间)
      •      5)本地方法栈
  • 三、垃圾回收与简单优化(包含堆内存具体流程)
    •    1、堆中对象的流转
      •      1)堆内存对象的流转
      •      2)使用工具查看堆内存对象的流转
    •    2、垃圾回收机制
      •      1)gc root
      •      2)gc 中的关系链
      •      3)STW
      •      4)是否是垃圾对象的判断
    •    3、针对堆内存做的 JVM参数 配置简单优化
      •      1)对象被放进Old区的部分情况
      •      2)上述案列在堆内存中的流程

一、JDK、JRE、JVM关系图解

JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第1张图片
JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第2张图片
   上图中,展示了 不同 JDK 版本中的 JVM 对不同操作系统在底层硬件和指令上的处理 ;同时,通过 javac 指令产生的 .class 文件对于不同的 JVM 都是可以运行的,故而同一套的 java 程序可以不同操作系统上运行

二、JVM虚拟机

   如果想要学习 JVM 底层运行步骤,可以利用 idea 的Open in Terminal 或者 命令行界面,进入到对应的 .class 文件路径,输入 javap -c 类名.class > 文件名.txt ;将程序的字节指令码保存到指定的文件中,至于路径,就是 .class 文件所在路径
   注意: 字节指令码各自含义,可参考 JVM指令手册

   1、JVM虚拟机的组成

     主要有:类装载子系统、运行时数据区(内存模型)、字节码执行引擎
JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第3张图片

   2、字节码执行引擎

        字节码执行引擎作用:
        (1)修改程序计数器中的数值
        (2)java 程序利用 javac 命令转换成为.class文件(指令文件)之后,由字节码执行引擎执行

   3、运行时数据区(内存模型)

     1)堆(heap)

       存放 new 出来的对象
       堆的划分:其中默认,Old区占堆的2/3;Eden区和Survivor区共占1/3;Eden区占1/3的80%,而Survivor区占1/3的20%;Survivor区的两个部分,是平分的;Eden区与Survivor区合称为年轻代
       (1)Eden区:伊甸园区(亚当夏娃相遇的地方,也就是新生的开始),又称青年代
       (2)Survivor区:幸存区,又称中年代;平均分为两部分,Survivor0区和Survivor1区
       (3)Old区:永久区,又称老年代
     对象在堆中的具体流转,在之后与垃圾回收、简单优化一起;可见 第三部分:垃圾回收与简单优化(包含堆内存具体流程)

     2)栈(stack)

       又称为 线程栈 ,存放 局部变量
       栈:遵循 FILO(先进后出)原则
JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第4张图片
         上述程序中,在main线程中,main方法调用了compute方法
         注意: 一个方法对应一个栈帧内存区域;每个方法各自的局部变量存放在自己的栈帧内存区域
JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第5张图片
         栈又分为局部变量表、操作数栈、动态链接、方法出口等
         (1)局部变量表:顾名思义,存放局部变量的地方
         (2)操作数栈:临时存放操作数的区域,之后会将操作数与局部变量关联,放入局部变量表;操作数,有点类似于数据值(如上述程序中的1、2、10)
         (3)动态链接:
         (4)方法出口:记录调用该方法的地方及行数

     3)程序计数器

        记录线程运行到的位置,主要是在多线程运行切换时使用到
        每运行一行代码时,都要修改一次,而这个修改,就是由 字节码执行引擎 来修改的

     4)方法区(元空间)

       java1.8之前称为永久态,java1.8及以后又称为元空间
       存放常量、静态变量、类信息、方法信息;其实就是不会改变的一些数据信息

     5)本地方法栈

       java语言是1995年面世的,之前程序都是使用C语言等实现的;java面世之后,java程序调用C程序就是本地方法调用的
       当然,在后来,随着技术的发展,出现了很多跨语言调用的技术,也就不再使用本地方法调用了
       本地方法用关键字 native 修饰
       而每个本地方法在运行过程中,也是需要使用到内存;就是本地方法栈
   堆、栈、方法区、本地方法栈关系图:
JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第6张图片

三、垃圾回收与简单优化(包含堆内存具体流程)

   1、堆中对象的流转

JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第7张图片

     1)堆内存对象的流转

     当Eden区内存满了的时候,触发第一次的minor gc(小范围垃圾回收,即检测年轻代范围);将非垃圾对象移动到Survivor0中(标记加1),而垃圾对象直接被清除。
     当Eden区第二次满了的时候,也做同样操作;不过此时会将Survivor0一起扫描,然后将非垃圾对象移动到Survivor1中(标记加1),而垃圾对象直接被清除。
     第三次的时候,再移动至Survivor0中;如此循环。当标记达到15时,就会被直接放入到Old区当中

     2)使用工具查看堆内存对象的流转

     使用命令行界面,输入 jvisualvm 指令,调出工具;在工具中,安装visual gc插件;安装好后,即可使用

   2、垃圾回收机制

     当Old区内存满了的时候,就会触发 full gc(大范围垃圾回收,即检测整个堆范围)
     而不管是 minor gc 还是 full gc 都是由字节码执行引擎来执行的

     1)gc root

     从上一部分讲述的堆、栈、方法区、本地方法栈关联出发;其实,gc root 就是栈中的局部对象变量、方法区中静态对象变量、本地方法栈中的对象变量

     2)gc 中的关系链

     利用 gc root 来开始,往堆内存中查找 new对象,new对象 中可能又存在对象,故而就这么一直查找下去,直到一个 new对象 中完全没有对象;这样就会形成一个对象之间的关系链

     3)STW

     在程序进行 gc 操作的时候,会将整个程序都进行停止;称为 Stop-The-World
     在 minor gc 时,STW时间极短,都可以忽略不计的;而 full gc 时,由于是整个堆范围进行 gc ,故而会STW较久,故而会出现性能问题,故而需要尽可能的减少 full gc 的次数

     4)是否是垃圾对象的判断

     当一个方法运行结束后,栈中的局部对象变量、方法区中静态对象变量、本地方法栈中的对象变量就会被清除;也就是 gc root被清除;这就会造成 gc关系链无根,那么关系链中余下的所有对象就都是垃圾对象

   3、针对堆内存做的 JVM参数 配置简单优化

     通过案例,讲解对JVM参数配置的简单优化
JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第8张图片
JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第9张图片

     1)对象被放进Old区的部分情况

       (1)对象标记达到了15:
       (2)对象动态年龄判断:当一个对象的内存大小达到或超过Survivor0(或者是Survivor1)内存的50%时,会直接被放入Old区

     2)上述案列在堆内存中的流程

JDK体系和JVM架构(内存、垃圾回收、简单的优化)_第10张图片
       线程运行每秒产生60MB对象,13秒达到Eden区内存极限,进行minor gc前12秒的 12 * 60MB会被直接清除,但最后一秒的60MB会放入Survivor0;这时,60MB超过了Survivor0的50%,就会被直接放入Old区;那5、6分钟之后,Old区就会满内存,进行 full gc
       每5、6分钟进行一次 full gc,太过于频繁;STW严重;故而要优化
       优化方案:
在这里插入图片描述
     在原来的JVM参数配置中,加入了 -Xmn2048M ;该参数意思就是设置年轻代(即Eden区加Survivor区)内存大小;此时,Eden区就是1600MB,Survivor0和Survivor1各是200MB;这时Eden区就是26秒左右才会满,而60MB又小于Survivor0的50%;故而不会被放入Old区,也就降低了 full gc 的次数,减少STW的次数

你可能感兴趣的:(JVM,JDK,内存)