JVM学习总结

1 篇文章 0 订阅

JVM

本文主要记录学习JVM的一些学习笔记,讲师是bilibili up主:狂神说Java
参考书:《深入理解Java虚拟机》

一些 JVM相关面试题

  • 请你谈谈你对JVM的理解?Java8虚拟机和之前的变化更新?
  • 什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
  • JVM的常用调优参数有哪些?
  • 内存快照如何抓取,怎么分析Dump文件?知道吗?
  • 谈谈JVM中,类加载器你的认识?

JVM的位置

在这里插入图片描述

JVM的体系结构

在这里插入图片描述

在这里插入图片描述

Java内存模型

线程私有

栈(Java虚拟机栈)

先进后出,后进先出

栈内存,主管程序的运行,生命周期和线程同步;线程结束,栈内存就立即释放,对于栈来说,不存在垃圾回收问题

基本类型对象(byte、short、int、long、float、double、boolean、byte)

局部变量表:存放局部变量–堆内存中对象的地址

操作数栈

动态链接:比如调用其他方法,就用动态链接将相应方法压入栈

方法出口

本地方法栈

存放native方法

native

凡是带了native关键字的,说明java的作用范围达不到了,会去调用底层C语言的库,会进入本地方法栈,调用本地方法接口(JNI,Java Native Interface,作用:扩展Java的使用,融合不同的编程语言为Java所用!最初:C、C++),Java诞生的时候,C、C++横行,想要立足,必须要有调用C、C++的程序,它在内存中专门开辟了一块标记区域:Native Method Stack(本地方法栈),登记native方法 ,在最终执行的时候,通过JNI加载本地方法库中的方法

PC寄存器(程序计数器)

可以理解为jvm执行到当前字节码的行号, 比如cpu被抢占,jvm需要记录位置来继续执行

唯一不会出现内存泄漏的区域

线程共有

Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。

类加载器读取了类文件后,一般会把类、方法、常量、变量等所有引用类型的真实对象保存到堆中

唯一目的就是存放对象实例,几乎所有的对象实例以及数组都要在这里分配内存

新生区(年轻代、伊甸园区)
Edan Space(伊甸园区)

new出来的对象放在edan,通过minor gc,方法是gc root,查找对象引用的根来查找 没有被引用的对象。占8/10

from survivor(幸存0区)

占1/10

to survivor(幸存1区)

占1/10

为什么要有两个survivor,避免内存碎片化, survivor回收后的内存空间不连续,可能无法存放大对象。

养老区(老年代)

大概占堆内存2/3,占满会引发full gc

永久区(永久代)

jdk1.8被删除,jdk1.8以后更改为元空间

这个区域是常驻内存的。用来存放Jdk自身携带的Class对象,Interface元数据,存储的是Java运行时的一些环境或类信息,这个区域不存在垃圾回收,关闭VM虚拟机就会释放这个区域的内存。

  • 在 jdk1.6(含)之前也是方法区的一部分,并且其中存放的是字符串的实例;
  • 在 jdk1.7(含)之后是在堆内存之中,存储的是字符串对象的引用,字符串实例是在堆中;
  • jdk1.8 已移除永久代,字符串常量池是在本地内存当中,存储的也只是引用。

在这里插入图片描述

方法区(元空间)

元空间的本质和永久代类似,都是对JVM规范中方法区的实现 并不在虚拟机中,而是在本地内存

启动时创建,所有线程共享

可以选择不实现垃圾收集

新版本中是存储在堆内存中的

常量,静态变量引用,类信息,方法代码,常量和静态变量也是存的堆内存中对象地址

运行时常量池,存放编译期生成的各种字面量和符号引用

类加载器

作用:加载Class文件

在这里插入图片描述

分类

BootstrapClassLoader(启动类加载器)

是JVM自带的类加载器,负责Java核心库,用来装载核心类库。该加载器无法直接获取。 rt.jar

c++编写,加载java核心库 java.*,构造ExtClassLoaderAppClassLoader。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作

ExtClassLoader (标准扩展类加载器)

负责jre/lib/ext目录下的jar包或者-D java.ext.dirs指定目录下的jar包装入工作库

java编写,加载扩展库,如classpath中的jrejavax.*或者java.ext.dir 指定位置中的类,开发者可以直接使用标准扩展类加载器。

AppClassLoader(系统类加载器)

java编写,加载程序所在的目录,如user.dir所在的位置的`class

负责java -classpath 或 -D java.class.path所指的目录下的类与jar包装入工作,是最常用的类加载器

CustomClassLoader(用户自定义类加载器)

java编写,用户自定义的类加载器,可加载指定路径的class文件

双亲委派机制

当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

流程

在这里插入图片描述

作用
  1. 防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
  2. 保证核心.class不能被篡改。通过委托方式,不会去篡改核心.class,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

沙箱安全机制(了解)

JVM调优

目的

目的是减少STW(stop the world)时间, 所有GC都会引发STW,暂停用户进程

常用参数

参数名称含义** 默认值**** 备注**
-Xms初始堆大小物理内存的1/64(<1GB)默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
-Xmx最大堆大小物理内存的1/4(<1GB)默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
-Xmn年轻代大小(1.4or lator)** 注意**:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小. 增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
-XX:NewSize设置年轻代大小(for 1.3/1.4)
-XX:MaxNewSize年轻代最大值(for 1.3/1.4)
-XX:PermSize设置持久代(perm gen)初始值物理内存的1/64
-XX:MaxPermSize设置持久代最大值物理内存的1/4
-XX:+PrintGCDetails输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]
-XX:+HeapDumpOnOutOfMemoryError生成OOM错误的dump文件

GC(垃圾回收)

作用区域

在这里插入图片描述

JVM在进行GC时,并不是对着三个区域统一回收,大部分时候,回收都是新生代

  • 新生代
  • 幸存区(from survivor、to survivor)
  • 老年区

GC两种类型:轻GC(普通的GC),重GC(全局GC)

GC常见题目

  1. JVM的内存模型和分区,详细到每个区防渗膜?
  2. 堆里面的分区有哪些?Eden、From survivor、To survivor、老年区,说说他们的特点
  3. GC的算法有哪些?标记清除法、标记压缩、赋值算法、引用计数器、怎么用的?
  4. 轻GC和重GC分别在什么时候发生?

基本机制

分代收集,所有GC都会引发STW

垃圾搜索算法

引用计数法

对象中存在一个引用计数器,一旦该对象被引用则计数器加1, 一旦对象应用被释放,则计数器减1。因为这种算法无法解决相互引用的问题,所有虚拟机并没有使用这个垃圾搜索算法。

在这里插入图片描述

可达性分析算法

遍历所有的GC Roots,从GC root开始可达的为存活对象,不可达的为待gc对象。

GC Roots的条件:

  • 栈桢的局部变量表所引用的对象
  • 方法区的静态变量和常量所引用的对象
  • 本地方法栈的JNI所引用的对象

垃圾清除算法

复制算法

主要用于年轻代

内存划分为空闲区域和活动区域,把可达对象复制到空闲区域, 空闲区域变为活动区域,清空之前的活动区域,变为空闲区域

在这里插入图片描述
在这里插入图片描述

好处:没有内存碎片

坏处:浪费内存空间,有一半空间永远是空to survivor

复制算法最佳使用场景:对象存活度较低的时候(主要是在新生区的时候)

标记-清除算法

从GCROOT开始,如果是可达对象标记为存活对象,然后对不可达对象进行清除

在这里插入图片描述

优点:不需要额外的空间

缺点:两次扫描,浪费时间,会产生内存碎片

标记-压缩算法

对标记-清除算法进行优化,防止内存碎片产生
在这里插入图片描述

总结

内存效率:复制算法>标记-清除算法>标记-压缩算法(时间复杂度)

内存整齐度:复制算法=标记-压缩算法>标记-清除算法

内存利用率:标记-压缩算法=标记-清除算法>复制算法

思考:有没有最优的算法?

没有。没有最好的算法,只有最合适的算法------>GC:分呆收集算法。

年轻代:

  • 存活率低
  • 复制算法

老年代:

  • 区域大
  • 存活率高
  • 标记-清除和标记-压缩混合实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值