一,前言

大家好,我是小墨。

这一章我们介绍下jvm知识基础,众所周知,运行一个 Java 应用程序,我们必须要先安装 JDK 或者 JRE 包。这是因
为 Java 应用在编译后会变成字节码,然后通过字节码运行在 JVM 中,而 JVM 是 JRE 的核心组成部分,jvm不仅做了

java字节码的分析和执行,同时也进行了自动内存分配管理机制,使得大家开发是不需要关注对象的内存分配和回收,

但是如果我们能够对jvm了解更深,我们将拥有内存的管理能力,进行jvm层次调优,提升我们的应用服务性能。

所以这一章我们将讲述jvm运行原理,内存模型,gc算法等,为我们后面进行jvm的调优做准备。

 

二,jvm内存模型

jvm内存模型主要分为堆,程序计数器,方法区,虚拟机栈和本地方法栈,如图,我们注意,

线程共享的有堆,方法区,其他都是线程隔离,生存周期和该线程一起共生同死

【小墨java】jvm之一-----jvm基础

  • :几乎所有对象和数组都被分配到了堆内存中,
  • 方法区1.8以前是方法区,1.8以后叫元空间-MetaSpace方法区主要是用来存放已被虚拟机加载的类相关信息,包括类信息、运行时常量池、字符串常量池。类信息又包括了类的版本、字段、方法、接口和父类等信息。           在加载类时候,class 文件中除了有类的版本、字段、方法和接口等描述信息外,还有一项信息是常量池 (Constant Pool Table),用于存放编译期间生成的各种字面量和符号引用。字面量包括字符串(String a=“b”)、基本类型的常量(final 修饰的变量),符号引用则包括类和方法的全限定名(例如 String 这个类,它的全限定名就是Java/lang/String)、字段的名称和描述符以及方法的名称和描述符
     
  • 虚拟机栈是线程私有的内存空间,存放基本类型的变量数据和对象的引用。但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(对象可能在常量池里)(字符串常量对象存放在常量池中。)                                           当创建一个线程时,会在虚拟机栈中申请一个线程栈,用来保存方法的局部变量、操作数栈、动态链接方法和返回地址等信息,并参与方法的调用和返回。每一个方法的调用都伴随着栈帧的入栈操作,方法的返回则是栈帧的出栈操作
  • 程序计数器:主要用来记录各个线程执行的字节码的地址,例如,分支、循环、跳转、异常、线程恢复等都依赖于计数器
  • 本地方法栈:本地方法栈则用于管理本地方法的调用。但本地方法并不是用 Java 实现的,而是由 C 语言实现的,native方法

堆详解

【小墨java】jvm之一-----jvm基础

【小墨java】jvm之一-----jvm基础

上图显示了堆的具体分区和java7 java8的对比,具体如下:

  1. 堆划分为新生代和老年代,新生代分为EdenSurvivor,Survivor区又可以FromSurvivor和ToSurvivor
  2. 默认新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 )
    默认的,Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),即: Eden = 8/10 的新生代空间大小,from = to = 1/10 的新生代空间大小
  3. Java7及以前版本的Hotspot中方法区位于永久代中。Java8中新增了元空间(Metaspace),方法区存在于元空间(Metaspace)。同时,元空间不再与堆连续,而且是存在于本地内存(Native memory)

java7 8 堆改进的好处:内存隔离,当Java Heap空间不足时会触发GC,但Native memory空间不够却不会触发GC。

三,类编译加载执行

【小墨java】jvm之一-----jvm基础

一般一个java文件需要经过编译---》加载进虚拟机----》运行时编译成机器码   然后开始运行,被我们调用。我们再来了解下多个父子类怎么调用加载。

双亲委托模型

【小墨java】jvm之一-----jvm基础

JVM去加载一个类,首先会委派给自己的父类加载器去加载,没有找到则会继续向上委托,直到顶层的引导类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。

通过这种方式,有了层次的加载关系,防止重复加载。


四,垃圾回收机制

来到我们的重头戏垃圾回收机制,我们这一节就针对三个问题展开讲述:

  1. 回收发生在哪里
  2. 对象何时可以被回收
  3. 如何回收对象

回收发生在哪里

       程序计数器、虚拟机栈和本地方法栈这 3 个区域是线程私有的,随着线程的创建而创建,销毁而销毁;栈中的栈帧随着方法的进入和退出进行入栈和出栈操作,每个栈帧中分配多少内存基本是在类结构确定下来的时候就已知的,因此这三个区域的内存分配和回收都具有确定性。
        垃圾回收的重点就是关注堆和方法区中的内存了,堆中的回收主要是对象的回收,方法区的回收主要是废弃常量和无用的类的回收

对象何时可以被回收

一般判断对象不再被引用时可以被回收。目前是使用以下算法来判断:引用计数,可达性分析算法。主要是使用可达性算法。

  1. 引用计数算法:一个对象的引用计数器来判断该对象是否被引用了。每当对象被引用,引用计数器就会加 1;每当引用失效,计数器就会减 1。当对象的引用计数器的值为 0 时,就说明该对象不再被引用,可以被回收了。它存在着对象之间相互循环引用的问题,不建议使用
  2. GC Roots 是该算法的基础,GC Roots 是所有对象的根对象,在 JVM加载时,会创建一些普通对象引用正常对象。这些对象作为正常对象的起始点,在垃圾回收时,会从这些 GC Roots 开始向下搜索,当一个对象到 GC Roots 没有任何引用链相连时,就证明此对象是不可用的。目前HotSpot使用这种方法。
  3. JDK1.2后引用概念分为以下四种:【小墨java】jvm之一-----jvm基础

如何回收对象

这一部分内容挪到下一节,对于如何回收对象,我们需要了解:

  1. 在jvm内存模型中对象的生命周期
  2. 使用什么算法进行垃圾回收
  3. 垃圾算法如何回收

 

五,垃圾回收

 

jvm内存模型中对象的生命周期

 在这一节中我们要了解对象在我们的jvm内存模型中的 新生代Eden,Survivor,老年代如何流转的

新生代对象生命周期

  1. 对象优先分配到新生代的Eden区
  2. 运行一段时间后,新生代Eden 区满了会触发minor GC,复制存货对象到S1(FromSurvivor),清空Eden。
  3. Eden区再次满了,触发MinorGC,复制Eden+S1存活对象到S2(ToSurvivor)
  4. Eden区和S1(FromSurvivor)区清空,再次开始分配对象
  5. 在新生代的回收过程中始终保持一块S区空着,保证这个循环能够继续

老生代对象生命周期

  1. 一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1,并且对象的年龄还会加 1(Eden 区->Survivor 区后对象的初始年龄变为 1),当它的年龄增加到一定程度(默认为 15 岁,可以修改-XX:MaxTenuringThreshold),就会被晋升到老年代中
  2. 老年代也满了,就会触发FullGC,把老年代里没人引用的垃圾对象清理掉,然后再分配。
  3. 大对象直接放入老年代,阈值可以设置:-XX:PretenureSizeThreshold
  4. 如果FullGC后仍然无法存储对象,JVM抛出OOM内存溢出异常

 

GC算法

以下是目前常用的四个GC算法,

【小墨java】jvm之一-----jvm基础

我们要注意以上这几种算法是相互配合的,并不是独立的。

 

垃圾收集器

对于垃圾收集器的选择我们先要关注几点

  1. 并行能力:CPU多核下可以进行并行计算
  2. 响应时间:垃圾收集器进行对象碎片整理时需要暂停系统操作,这时会导致此时无法进行服务请求处理,希望系统停顿时间尽可能短的,得选择更合适的垃圾收集器
  3. 吞吐量:运行用户代码时间/(运行用户代码时间+垃圾回收时间)

 

针对以上GC算法诞生了几种垃圾收集器:

【小墨java】jvm之一-----jvm基础

总结而言:

  • client端单核建议Seral收集器
  • java8 server端默认Parallel scavenge收集器 + Parallel Old,注重吞吐量以及 CPU 资源的场合
  • java9开始建议设置G1 收集器为默认收集器,最高级,集大成者,满足低停顿,高吞吐

四,总结

这篇jvm基础介绍了jvm的基本内容,和GC算法内容,下篇文章将根据实际例子来讲解jvm调优,欢迎评论点赞,谢谢。

 

参考文章:

jvm原理解惑篇

javaGuide jvm机制

《极客时间--调优实战》

相关文章:

  • 2021-12-20
  • 2021-08-12
  • 2021-09-16
  • 2021-12-15
  • 2021-05-06
  • 2022-12-23
  • 2022-12-23
  • 2021-09-10
猜你喜欢
  • 2021-04-03
  • 2021-05-18
  • 2022-01-08
  • 2021-05-05
  • 2021-08-13
  • 2021-05-24
相关资源
相似解决方案