java-JVM

JVM

jvm概述

对java程序的运行过程更加的了解

中高程序员的必备技能 项目管理 性能调优

jvm的作用

.class文件 开发阶段

jvm将字节码文件加载到虚拟机中

在将字节码文件 解释/编译为机器码

管理运算时的数据存储,垃圾回收

现在的jvm还可以执行其他语言编译后的字节码文件

jvm的构成

  1. 类加载系统

负责从硬盘上加载字节码文件到jvm中。

  1. 运行时数据区

按照不同的数据分区进行储存(方法区,堆,栈,本地方法栈,程序计数器)

  1. 执行引擎

将字节码再次编译/解释为机器码

  1. 本地库接口

调用本地操作系统方法

jvm结构-类加载

负责从硬盘上加载字节码文件到jvm中

类加载的过程

  1. 加载

以二进制字节流的方式加载字节码

在内存中为类生成一个class对象,将静态存储转换为运行时存储

  1. 链接

验证:

(1)检验被加载的字节码格式是否正确(.class文件的特定格式)

(2)验证语法是否存在 (例如继承了父类但是父类不存在,是否继承的不能被继承的类)

准备:

为类的静态属性分配内存,并设置默认初始值

(例如在类中 有代码 static a=10,在初始化之前会为a赋默认值0)不包含用final修饰的static常量,在编译期间进行初始化

解析:

将 二进制中的符号引用替换成直接引用

(符号引用是 Class 文 件的逻辑符号,直接引用指向的方法区中某一个地址)

  1. 初始化

对类变量(静态变量)进行赋值

类什么时候会被初始化?

  1. 使用类中的静态变量,静态方法
  2. 在类中运行main方法
  3. 创建对象
  4. 使用反射加载一个类
  5. 当初始化 一个类的子类时,且优先加载父类

注意:当使用一个类中的静态常量时 ,类并不会初始化,因为在建议时已经给赋值

当类在加载阶段初始化完成,才说明类的整体加载过程完成。

类加载器

真正实现类加载

宏观:
  1. 引导类(启动类)加载器

不是用java语言实现的,c/c++,jvm实现

  1. 其他类加载器

用java语言写的实现类,都继承java.lang.ClassLoader

微观:
  1. 引导类(启动类)加载器

java中系统提供的类,都是由启动类加载器加载,例如 String

  1. 扩展类加载器

Java 语言编写的,由 sun.misc.Launcher$ExtClassLoader 实现.

派生于 ClassLoader 类.

从 java.ext.dirs 系统属性所指定的目录中加载类库,或从 JDK 系统安装目录的

jre/lib/ext 子目录(扩展目录)下加载类库.如果用户创建的 jar 放在此目录下,也

会自动由扩展类加载器加载

  1. 应用程序类加载器(系统类加载器)

Java 语言编写的,由 sun.misc.Launcher$AppClassLoader 实现.

派生于 ClassLoader 类.

加载我们自己定义的类,用于加载用户类路径(classpath)上所有的类.

该类加载器是程序中默认的类加载器

  1. 自定义的类加载器

例如 自己写一个类继承ClassLoder

例如tomcat就有自己的加载器

注意:应用程序类加载器由扩展类加载器加载,扩展类加载器由引导类加载器加载

双亲委派机制

成加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制.

如果均加载失败,就会抛出 ClassNotFoundException 异常

工作原理:
  1. 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请 求委托给父类的加载器去执行.
  2. 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终 将到达顶层的启动类加载器.
  3. 如果父类加载器可以完成类的加载任务,就成功返回,倘若父类加载器无法完
双亲委派优点?

安全,可避免用户自己编写的类替换 Java 的核心类,如 java.lang.String.

如何打破双亲委派机制

通过自定义类架加载器,重写ClassLoader类中的findClass()。

tomcat这种容器也会自定义类加载器

运行时数据区

程序计数器

作用:用来记录程序执行指令的位置。

特点:
  1. 内存空间小,运行速度快
  2. 每个线程都有自己的程序计数器,是线程私有的(每个线程都有一个计数器),生命周期与线程相同。
  3. 它是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError(内存溢出)情况的 区域.不会有垃圾回收。

虚拟机栈

栈是运行单位,管理方法(javazij自己写的方法)运行,调用方法入栈,运行完毕出栈。

栈是线程私有的。

不会有垃圾回收,但是会出现栈溢出。

栈帧

一个方法入栈,就可以看做是一个栈帧的产生。

两种情况惠弹出栈帧 return 或者出现异常

栈帧的构成:

  1. 局部变量表

  2. 操作数栈

  3. 方法的返回地址

本地方法栈

管理运行本地方法的调用

本地方法:native关键字修饰的方法,没有方法体

Object hashCode()

​ getClass()

​ clone()

​ notify()

​ wait()

IO read()

Thread start0()

线程私有,也会出现内存溢出问题,不会垃圾回收

由C编写

存放程序中产生的对象

线程共享

会内存溢出,会进行垃圾回收,是垃圾收集器的重点区域

堆空间是运行时数据区中最大的一个空间

大小可以调节

堆内存区域划分:

新生代:

​ 伊甸园区:刚创建的对象存放在伊甸园区

​ 幸存者区1:存放伊甸园区和另一个幸存者区经过垃圾回收存活下来的对象,两个幸存者区可以交替使用,始终有一个区域是空闲的。

​ 幸存者区2

老年代:存放生命周期长的对象,非常大的

经历过15次垃圾回收依然存在的对象,就会被存放在老年代。

为什么要分区?

根据不同对象的存活时间进行划分,生命较长的对象放在老年代,减少垃圾回收的频率和扫描次数。

对象的创建以及在内存中的分布过程
  1. 新创建的对象存放在伊甸园区

  2. 当垃圾回收时,将伊甸园区的对象移入幸存者0区中

  3. 允许运行,新创建的对象还是保存在伊甸园区

  4. 下一次垃圾回收时,将伊甸园的对象和幸存者0区的对象移入幸存者2区中,交替执行

  5. 若一个对象经历15次垃圾回收后任然存活,则将其移入老年代中。

为什么是15次?

在对象中其年龄用4个比特位保存,多以最大为1111即是十进制15,可以设置次数,但是最大值为15次。

老年代和新生代比例 2:1

伊甸园和两个幸存者区的比例8:1:1

堆空间的参数设计

(jvm调优就是根据程序实际运行的需要设置参数,调整各个区间占比大小)

垃圾回收的名词:

Minor GC 是针对新生代的垃圾回收 频繁进行

Major GC 是针对老年区进行的垃圾回收 较少进行

FULL GC 整堆收集 实际开发中,尽量避免整堆收集

什么时候触发整堆收集:
  1. 老年代空间不足时
  2. 方法区空间不足时

方法区

主要村出纳加载到虚拟机的类信息。

线程共享的,会溢出。

可以调节大小。

方法区大小可以使用参数-XX:MetaspaceSize 指定

方法区的垃圾回收

方法区是存在垃圾回收的,只不过条件比较苛刻。由于卸载条件比较苛刻,一般情况下我们认为类不狐疑被卸载。

回收条件

1.该类所有的实例都已经被回收,也就是 Java 堆中不存在该类及其任何派生子类的实例。

2.加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加 载器的场景,如 OSGi、JSP 的重加载等,否则通常是很难达成的。

3.该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

本地方法接口

1、什么样的方法是本地方法?

被native关键字修饰的方法

本地方法不是Java语言实现的,是由参佐系统实现的。

2、Java种为什么会调用本地方法?

因为上层高级语言没有对底层硬件直接操作的权限,而是要调用操作系统提供的接口进行访问。

执行引擎

负责将装载搭配虚拟机中的字节码编译成机器码。

概念区分:

1.前端编译:从 Java 程序员-字节码文件的这个过程叫前端编译.

2.执行引擎这里有两种行为:一种是解释执行,一种是编译执行(这里的是后端

编译)

.Java-javac 前端编译–>.class

.class—执行引擎---->机器码

什么是解释器?什么是 JIT 编译器?

解释执行:是用一个解释器对代码逐行进行解释执行,一帮常见的脚本语言是解释执行 效率低,省去了编译时间

编译执行:是将某一段代码进行整体的编译,执行编译后的结果 效率高,需要编译时间。

Java的执行引擎采用的是半解释半编译的方式,将字节码转换为机器码。程序刚开始运行时,立即采用逐行解释执行。

程序运行中会将热点代码编译并缓存起来,这样两者结合使用提高运行效率。

垃圾回收

什么是垃圾?

垃圾是指在运行程序中没有任何引用指向的对象,这个对象就是需要被回收的垃圾。垃圾对象需要被清理回收,否则就一直占用内存空间,其他对象无法使用垃圾对象所占用的空间,严重的话会造成内存溢出。

早期的垃圾回收

早期例如c//c++是需要程序员在程序中手动对不再使用的对象进行删除释放。给程序员造成成的繁重的工作量,万一忘记了回收,会造成内存泄漏。

垃圾回收的区域

垃圾回收涉及堆,方法区

重点是堆(新生代频率高,老年代频率高)

较少回收方法区

内存溢出

经过垃圾回收后,内存依然不够使用,导致程序崩溃

内存泄漏

一个对象在程序中不会被使用但是垃圾收集器又不能回收,一直会占用内存空间,久而久之也是造成了OOM的原因之一

例如:单例模式中单例对象使用唯一一个的对象

数据库连接对象

Socket

IO等对象

使用玩应该close关闭资源,若不关闭,回收器无法回收这些对象。

STW stop the word

当垃圾回收时(标记,回收),会导致其他用户线程不再进行,保证分析的准确性。

垃圾回收算法

标记阶段

标记出那些对象是垃圾对象

引用计数算法(未被使用)

在对象中有一个计数属性,只要有对象指向该对象,计数器加1,计数器的值若为零则表示此对象是垃圾对象。实现简单

缺点:

  1. 它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。

  2. 每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。

  3. 引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一条致命 缺陷,导致在.Java 的垃圾回收器中没有使用这类算法

可达性分析算法 (根搜索算法、追踪性垃圾收集)

思路: 从一些活跃对象(GCRoots)搜索,与根对象相关联的对象都是被使用的,与根对象或者根对象相关的 引用链不相关的对象,就称为垃圾对象。

那些对象可以被称为根对象?
  1. 虚拟机汇总后(正在运行的方法)被引用的对象
  2. 类中静态属性
  3. 被用来当做同步锁
  4. java中系统的类
对象的finalize()方法

Object类中

protected void finalize()throwable Throwable{ }

在对象在被回收之前,可以在此方法中执行一些需要的逻辑。

当对象被判定为垃圾,在回收之前会调用finalize()方法,且此方法只会被调用一次。

不需要我们自己调用,由垃圾回收器调用

由于finalize()存在,

对象分为:

可触及的:不是垃圾对象

可复活的:被标记为垃圾对象,finalize()未被调用

不可复活的:被标记为垃圾对象,finalize()已被调用

回收阶段
标记-复制算法

可以有 多块二内存。每一次有一块儿是空闲的,将存活的对象移动到未被使用的空间中,清楚其他块儿中所有的对象。

优点:内存的碎片减少,适合存活对象少,垃圾对象对的场景。(新生代)

标记-清楚算法

存活位置不变,将垃圾对象记录在一个空闲的列表中,创建新对象时,若能放下则覆盖列表中的垃圾对象。(老年代)

不移动对象,回收后会产生内存碎片,故对齐改进产生了其他算法。

标记-压缩算法

将存活对象重新进行排列,排列到内存的一段,将其他的区域空间进行清理。进行标记清楚在进行压缩。

移动对象,进行了压缩,不会产生内存碎片,效率低下。

垃圾回收器

垃圾回收算法是理论,垃圾回收器是实践者。不同的厂商,不同的版本各自的实现方式各不相同。

分类:

在这里插入图片描述

按照线程数分
  1. 电线程垃圾回收器

    适用于小型简单的项目,只有一个线程进行垃圾回收。

  2. 多线程垃圾回收器

    适用于大型简单的项目,有多个线程进行垃圾回收。

按照工作模式分
  1. 独占式

    垃圾回收线程执行时,其他的用户线程暂停执行。

  2. 并发式

    垃圾回收线程可以和用户线程同时执行。

按照工作内存空间分
  1. 年轻代垃圾回收器
  2. 老年代垃圾回收器

CMS回收器

是首个实现垃圾收集线程和用户线程同时执行的

注意:不是所有都是并发执行的也会有独占执行的情况出现。

回收过程:
  1. 初始标记: 独占
  2. 并发标记: 并发
  3. 重新标记: 独占
  4. 并发清楚: 并发

G1(Garbage First)

适合大型服务器端,内存大,cpu更加先进的。

将每一个区域(伊甸园、幸存者、老年代)又划分成若干个小的区域,哪一个区域垃圾数量多,优先回收哪一个区域。可以做到整堆管理的收集。也可以做到并发执行。

  • 13
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值