JVM相关知识点总结

JVM内存模式

如图

在这里插入图片描述

  • 1、堆:存放对象实例,几乎所有的对象实例都在这里分配内存
  • 2、虚拟机栈:虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息
  • 3、本地方法栈:本地方法栈则是为虚拟机使用到的Native方法服务。
  • 4、方法区:存储已被虚拟机加载的类元数据信息(元空间)
  • 5、程序计数器:当前线程所执行的字节码的行号指示器
注意,JDK1.8把方法区PermGen(永久代)改为了Metaspace(元空间)
  • 原本永久代存储的数据:符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap
  • Metaspace(元空间)存储的是类的元数据信息(metadata)
  • 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。
  • 替换的好处:
    一、字符串存在永久代中,容易出现性能问题和内存溢出。
    二、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低
    三、因为固定大小,所以很难进行调优。另外,如果动态加载类过多,也容易产生OOM。

Java堆内存

虚拟机把堆内存划分成新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation)3个区域。

新生代

新生代由 Eden 与 Survivor Space(S0,S1)构成,大小通过-Xmn参数指定,Eden 与 Survivor Space 的内存大小比例默认为8:1,可以通过-XX:SurvivorRatio 参数指定,比如新生代为10M 时,Eden分配8M,S0和S1各分配1M。

  • Eden

大多数情况下,对象在Eden中分配,当Eden没有足够空间时,会触发一次Minor GC,虚拟机提供了-XX:+PrintGCDetails参数,告诉虚拟机在发生垃圾回收时打印内存回收日志。

  • Survivor:意思为幸存者,是新生代和老年代的缓冲区域。

当新生代发生GC(Minor GC)时,会将存活的对象移动到S0内存区域,并清空Eden区域,当再次发生Minor GC时,将Eden和S0中存活的对象移动到S1内存区域。

存活对象会反复在S0和S1之间移动,当对象从Eden移动到Survivor或者在Survivor之间移动时,对象的GC年龄自动累加,当GC年龄超过默认阈值15时,会将该对象移动到老年代,可以通过参数-XX:MaxTenuringThreshold 对GC年龄的阈值进行设置。

老年代

老年代的空间大小即-Xmx 与-Xmn 两个参数之差,用于存放经过几次Minor GC之后依旧存活的对象。当老年代的空间不足时,会触发Major GC/Full GC,速度一般比Minor GC慢10倍以上。

永久代

在JDK8之前的HotSpot实现中,类的元数据如方法数据、方法信息(字节码,栈和变量大小)、运行时常量池、已确定的符号引用和虚方法表等被保存在永久代中,32位默认永久代的大小为64M,64位默认为85M,可以通过参数-XX:MaxPermSize进行设置,一旦类的元数据超过了永久代大小,就会抛出OOM异常。

虚拟机团队在JDK8的HotSpot中,把永久代从Java堆中移除了,并把类的元数据直接保存在本地内存区域(堆外内存),称之为元空间。


GC垃圾回收

对象存活判断方法

判断对象是否存活一般有两种方式:

  • 引用计数法
    最简单,最高效,但一般不用它,因为它很难解决对象之间相互循环引用的问题。
  • 可达性分析法
    通过一系列成为“GC Roots”的对象作为起始点,从这些点开始向下搜索,当从GCRoots到一个对象不可达,则证明这个对象是不可用的。
在Java语言里,可作为GC Roots对象的包括如下几种:

a.虚拟机栈(栈桢中的本地变量表)中的引用的对象
b.方法区中的类静态属性引用的对象
c.方法区中的常量引用的对象
d.本地方法栈中JNI的引用的对象

GC算法

  • 1、标记-清除算法
    分为“标记”和“清除”两个阶段,它是最基础的收集算法,因为后续的算法都是基于这种思想并对其不足进行改进而得到的。它有两个不足:一是效率问题,二是空间问题,它会产生大量不连续的内存碎片。
  • 2、复制算法
    把可用内存划分为大小相等的两块,每次只用其中一块。用完后把存活的对象复制到另一块上,把已使用的一块一次清理掉,这样避免了内存碎片。
  • 3、标记-压缩算法(标记-整理算法)
    跟标记-清除算法一样,但后面不是直接对可回收对象清理,而是让存活对象向一端移动,把其它的清理掉。
  • 4、分代收集算法
    把内存分为新生代和老年代,采用各自适用的算法。新生代用复制算法,老年代用标记-清除或标记-压缩算法。

垃圾回收器

  • 串行收集器是最古老,最稳定以及效率高的收集器
  • 并行收集器,多线程方式收集
  • CMS回收器
    是回收停顿时间比较短,目前比较常用的垃圾回收器。它通过 初始标记、并发标记、重新标记、并发清除 四个步骤完成垃圾回收工作。第1,3步骤依然会引发STW。由于CMS采用的是标记——清除算法,所以会产生大量内存碎片。通过配置参数强制JVM在FGC完成后对老年代进行压缩,执行一次空间碎片整理,但也会引发STW。为了减少STW次数,配置参数,在执行了n次FGC后,JVM再对老年代执行空间碎片整理。
  • G1收集器,G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征。

类加载机制

类加载过程:加载、验证、准备、解析、初始化

如图

在这里插入图片描述

  • 加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类的对象
  • 连接,连接又包含三块内容:验证、准备、解析。
    • 1)验证,文件格式、元数据、字节码、符号引用验证;
    • 2)准备,为类的静态变量分配内存,并将其初始化为默认值;
    • 3)解析,把类中的符号引用转换为直接引用
  • 初始化,为类的静态变量赋予正确的初始值

接下来还有 使用和卸载两个生命周期。

双亲委派模型

  • 最高一层的类加载器:Bootstrap ClassLoader(启动类加载器),它是在JVM启动时创建的,通过C/C++实现的。
  • 扩展类加载器
  • 应用类加载器,记载用户定义的ClassPath路径下的类。
  • 自定义类加载器。实现步骤:继承ClassLoader,重写findClass()方法,调用defineClass()方法。

双亲委派机制:类加载器收到类加载请求,自己不加载,向上委托给父类加载,父类加载不了,再自己加载。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值