JVM

JVM

Java虚拟机(Java virtual machine),一种能够运行Java字节码的虚拟机。作为一种编程语言的虚拟机,实际上不只是,只要生成的编译文件匹配符合JVM对加载编译文件格式的要求,任何语言都可以有JVM编译运行。JVM有很多,不只是Hostspot,还有JRockit,J9等

JVM的基本结构

Java程序的运行的整个过程:

JVM有三个主要的子系统构成

  • 类加载子系统
  • 运行时数据区(内存结构)
  • 执行引擎

类加载机制

类的生命周期:加载–>验证–>准备–>解析–>初始化–>使用–>卸载,(其中验证–>准备–>解析都是属于连接的)

  1. 加载:将.class文件(字节码文件)从磁盘读到内存,将二进制字节流把文件加载到内存来,是通过全限定名(包名+类名)来读取的
  2. 连接:
    1. 验证:验证字节码文件的正确性(文件格式是否正确)
    2. 准备:给类的静态变量分配内存,并赋予默认值
    3. 解析:类装载器装入类所引用的其他所有类,就是把这个类所引用的其它类加载进来
  3. 初始化:为类的的静态变量赋于正确的初始值,上述的准备阶段为静态变量赋予的值是JVM默认的初始值,此处赋予的值才是编程者为变量分配的真正的初始值,执行静态代码块。
  4. 使用:通过执行引擎执行类中的方法
  5. 卸载:类的卸载:程序的正常的结束,异常,系统出现的错误。

类加载器的种类

  1. 启动类加载器(Bootstrap ClassLoader)(用C语言写的因为其加载的类可能是c语言写的):负责加载JRE的核心类库,例如JRE目标下的rt.jar ,charset.jar等。
  2. 扩展类加载器(Extension ClassLoader):负责加载JRE扩展目录ext中的jar类包。
  3. 系统类加载器(Application ClassLoader)(程序编写的类是有这个加载器加载):负责加载ClassPath路径下的类包
  4. 用户自定义加载器(User ClassLoader):负责加载用户自定义路径下的类包。

img

类加载机制

  1. **全盘负责委托机制:**当一个ClassLoader加载一个类的时候,除非显示的使用另一个ClassLoader,该类所依赖和引用的类也有这个ClassLoader载入
  2. **双亲委派机制(可以叫父类加载器):**先委托父类加载器寻找目标类,再找不到的情况下,再在自己的路径中去查找载入目标类
    1. 双亲委派机制的优点:
      1. 沙箱安全机制:例如自己写的String.class类不会被加载,这样可以防止核心库被随意篡改(自带的库函数不会被篡改)
      2. 避免类的重复加载:当父加载器加载了,子加载器的就不需要再加载一次。

打破双亲委派机制:

GC算法和收集器

GC算法

如何判断对象可以回收有引用计数法和可达性分析算法

​ **引用计数法:**给对象添加一个引用计数器,每当有一个地方引用,计数器就加一,当引用失效计数器减一(这个方法实现简单高效,但是主流虚拟机没有选者这个算法,因为很难解决对象之间循环引用的问题,例如A引用B,B又引用A,这样子A,B的计数器都无法为零,所以就无法会说这两个对象),计数器为零的对象不可能再被利用。

**可达性分析算法:**通过一系列的称为“GC Roots”的对象作为起点,从这些节点开始向下搜索,节点所走过的路径被称为引用链,当一个对象到GC Roots没有任何引用链的话,则证明此对象是不可用的。

GC Roots根节点:类加载器,Tread,虚拟机栈的局部变量表,static成员变量,常量引用,本地方法栈的变量等等

对象引用的四种:强引用,弱引用,软引用,虚引用。

**如何判断一个常量是废弃常量:**查看栈里的栈帧中的局部变量表里是否有引用,有就不是废弃变量否则是废弃变量。

如何判断一个类是无用的类:

需要满足以下三个条件:

  • 该类的所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
  • 加载该类的ClassLoader已经被回收
  • 该类对印的Java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法

虚拟机可以对满足上述三个条件的无用类可以进行回收,仅仅是可以,不是一定。

垃圾回收算法

**标记-清除算法:**把需要清除的对象标记出来,在标记完成后进行清除,

​ 不足的的地方:(1)效率不高 ;(2)标记清除后会产生大量的不连续碎片;

**复制算法:**把内存分为了两个大小相同的部分,每次只使用其中一块,当时用的这一块存满后回收一次,然后将存活的对象复制到另一个部分,然后下一次就是用这个部分进行回收,

**标记-整理算法:**标记过程跟标记-清除算法的标记过程一样但是对对象回收是不一样的,回收是将存活的对象向一段移动,然后直接清理边界以外的对象

**分代收集算法:**在不同的区域使用不同的垃圾收集算法:在新生代中每次都有大量的对象被回收,在伊甸区使用标记-清除算法, 在From-To区使用复制算法,在老年代中对象的存活的几率较大,没有额外的空间所以就会选择标记-整理算法

垃圾收集器

**Serial(串行)收集器:**新生代采用的是复制算法,老年代采用的是标记-整理算法。这个收集器简单而高效。配到GC会停掉用户线程

**ParNew收集器:**新生代采用的是复制算法,老年代采用的是标记-整理算法 ParNew收集器其实就是多线程版本依然会GC的时候会停掉用户线程,只是多开了几条线程GC,

**Parallel Scavenge收集器:**新生代采用的是复制算法,老年代采用的是标记-整理算法 Parallel Scavenge收集器类似于ParNew收集器,Parallel Scavenge收集器关注点是吞吐量(CPU的效率高),CMS等垃圾收集器关注点更多的是用户线程的停顿时间(提高用户的体验),吞吐量=CPU运行代码时间/CPU消耗的总时间;

**CMS收集器:**CMS是一个“标记-清除算法实现的”它的过程有:

  1. 初始标记:暂停所有的其他线程,并记录下直接与root相连的对象,数度很快
  2. 并发标记:同时开启GC和用户线程,用一个闭包结构去记录可达对象,但是在这个阶段结束,闭包结构并不能保证包含所有对象,因为用户可能会不断更新引用域
  3. 重新标记:为了修正在并发标记阶段因为用户线程继续运行而产生的一些对象。
  4. 并发清除:开启用户线程,同时GC线程对开始未标记的区域做清除

CMS主要优点:并发收集,低停顿,

CMS的缺点:(1)对CPU资源敏感 (2)无法处理浮动垃圾 (3)使用的回收算法“标记-清除”算法会导致大量空间碎片产生。

G1收集器:(Garbage-First)是一款面向服务器的垃圾收集器,主要是针对配备多颗处理器以及大容量的机器,以极高概率满足GC停顿时间要求的同时,还具备高吞吐量的特征。

G1收集器是被视为JDK1.7中Hotspot虚拟机的一更为重要进化特征,具备以下特点:

  1. 并发与并行:
  2. 分代收集:
  3. 可预测的停顿

G1收集器的运作大致分为以下步骤:

  1. 初始标记

  2. 并发标记:

  3. 最终标记:

  4. 筛选标记:

    JVM调优主要是调整俩个指标:(1)停顿时间:垃圾收集器做垃圾回收中断应用执行的时间 (2)吞吐量:垃圾收集的时间和总时间的占比

    GC的调优步骤:(1)打印GC日志 (2)

内存结构

共享:

:虚拟机启动时自动分配创建,用于存放对象的实例,几乎所有对象都在堆上分配内存,当对象无法在该空间申请到内存的话是会抛出异常的(OutOfMemoryError),同时也是垃圾收集器管理的主要区域。 堆分为新生代和老年代。

​ 新生代:类出生,成长,消亡的区域,一个类的在这里产生,应用,最后被垃圾回收器收集。新生代又可以分为甸园(Eden)和幸存区(Survivor区), 幸存区又分为From Survivor空间和 To Survivor空间。

​ 老年代:长期存活的对象和大对象。新生代中存储的对象,经过多次GC后仍然存活的对象会移动到老年代中进行存储。老年代空间占满后,会触发Full GC

​ 元空间:元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,1.7之前叫持久代,永久代,1.8叫元空间:都是为了实现JVM的方法区的实现。

img

方法区:存放的都是类的所有字段和方法字节码,以及一些特殊函数例如构造函数,接口代码也在这里定义,简单来说,所有定义的方法的信息多保存在该区域,静态变量+常量+类的信息(构造函数/接口定义)+ 运行时常量池,虽然JVM规范把方法去描述为一个堆逻辑部分,但是它却有一个别名叫作Non-Heap(非堆),目的就是为了和Java的堆区分开。

私有:

:栈里面放的是栈帧 栈帧释存放的是方法,栈帧里面放的才是方法的局部变量(放变量值的),操作数栈(放要计算的值的),动态链接(在运行的时候把类里面的一些符号引用转化成直接引用的过程),方法出口(返回地址)

img

本地方法栈:本地方法是由c语言和c++语言编写的,本地方法都是自带的方法(存放的是有=由native修饰的方法),不需要自己来实现的,

程序计数器:存放的接下来将要执行的代码序号

JDK的性能调优监控工具

Jinof

Jmap

686.png)

本地方法栈:本地方法是由c语言和c++语言编写的,本地方法都是自带的方法(存放的是有=由native修饰的方法),不需要自己来实现的,

程序计数器:存放的接下来将要执行的代码序号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值