JVM基础知识(周阳老师笔记

本文详细介绍了Java虚拟机的内存结构,包括类加载器、native方法、程序计数器、方法区、Java栈、堆内存以及垃圾回收算法。重点阐述了双亲委派机制、本地方法栈、堆内存的分区以及各种GC算法的工作原理。同时,文章提及了堆内存调优和日志信息解读,以及不同GC算法的时间效率和内存碎片情况。

在这里插入图片描述


一、类加载器

类装载器ClassLoader 负责装载我们java的字节码文件(.class) 而且class文件有特定的文件标识,类装载器会识别是否是 友善的 class文

Java虚拟机自带的加载器 有 3 + 1

  • 加载祖宗的是 Bootstrap(启动类加载器) 最顶层 (打印为null,因为是cpp写的,是祖宗最高级别)$JAVAHOME/jre/lib/rt.jar (rt:runtime)
  • 加载java扩展的extension(扩展类加载器) $JAVAHOME/jre/lib/ext/*.jar javax(x:extend)
  • 加载我们写的类 AppClassLoader(应用类加载器)

sum.misc.Launcher 是jvm的入口程序

  • 自定义类加载器 继承抽象类ClassLoader

双亲委派机制(parent delegation)就是每一个类加载器收到类加载请求时,他会先去找他的父类加载器,而不是自己先处理,即往上捅,只有父类反馈说没有的时候,子类才会尝试自己加载,从而能够保护恶意代码污染源代码,即沙箱安全

执行引擎(Execution Engine):视频没有详细说,ppt就一行字:负责解释命令,提交操作系统执行


二、native

java的native interface 本地方法接口 修饰的东西,是不需要java程序员了解,是java调用系统级别的方法,光靠java自己做不到了,不归java管了。需要调用第三方提供的接口(c/操作系统等),比如开启线程

早期c/c++横行的时候,java为了生存必须要调用c/c++程序,所以在内存中专门开辟了一块区域处理native代码,即本地方法栈,在Execution Engine执行时加载本地方法库

不过现在native方法越来越少,java主要是干微服务,异构领域通信发达


三、程序计数器

程序计数器嘛,就相当于是一个指针,用来存储下一条指令的地址,就是PC寄存器

即 指向方法区中的方法字节码,由执行引擎读取

如果执行的是Native方法的话,计数器则为空


四、方法区

方法区是规范,与具体实现无关。

方法区要求放java类的模板(每一个类的结构信息)就是Class文件,堆中的数据类型指向的方向

在不同的虚拟机里有不同的实现,如永久代(PermGen space)元空间(Metaspace)

是线程共享的,而且会发生垃圾回收


栈管运行,堆管存储

HotSpot是java虚拟机的一种实现,是Sun JDK 和 OpenJDK所带的虚拟机

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m79Bsmhm-1623845658156)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a05b3009-cd06-4295-ab79-eede49d683b7/Untitled.png)]

error级别和exception级别的错误的区别:

error不可处理,由jvm抛出的严重问题,需要直接修改程序

exception可以针对性处理


五、Java栈

存放八种基本数据类型+引用数据类型+实例方法

是线程私有的,一般不发生gc回收,只要线程结束,栈就随之结束

栈帧:栈中数据存在的格式

栈帧中存储3类数据:

  • 本地变量(Local Variables):输入输出参数和方法内变量
  • 栈操作(Operand Stack):记录入栈出栈操作
  • 栈帧数据(Frame Data):包括类文件、方法等

栈满会报StackOverflow错误 ,是error级别


六、堆

1.数据存放

逻辑分三种:

  • 新生代
  • 老年代
  • 永久代/ 元空间(方法区的一种实现)如rt.jar放进永久代

永久代的空间是在虚拟机中,元空间是在物理内存中

物理分两种:

  • 新生代
  • 老年代

新生代又分 伊甸区→幸存者0区→幸存者1区
伊甸区是GC = YGC

幸存者0区和幸存者1区又可以理解成from to区,gc清空伊甸区和from区,留存的对象去to区并生命周期+1,swap from and to,如果生命周期到了15还是存活,就进入老年代

养老区是 Full GC =FGC

Full GC多次,发现养老区没空间腾出来,就会报OOM错误(Out Of Memory)

内存空间的分配

Java虚拟机默认占本机物理空间的1/4

新生代占1/3堆空间 老年代占2/3堆空间

堆内存调优+日志信息解读

-Xmx 默认物理内存的1/4 -Xms 默认物理内存的1/64 -XX:+PrintGCDetails

我们也可以在idea中手动调参,实践中工程经验必须把初始值和最大值设置成一样,避免内存忽高忽低,jvm和系统争抢内存,产生停顿

2.GC回收算法

  • 引用计数法
  • 复制算法
  • 标记清除法
  • 标记整理法

Java的线程分为非守护线程和守护线程,GC是守护线程,只要JVM实例中有非守护线程,守护线程就要全部工作

  1. 普通GC(minor GC):常常发生在新生代的gc,因为新生代对象大多存活率都不高,所以minor GC经常发生

  2. 全局GC(major GC or Full GC):发生在老年代的gc,通常伴有一次minorGC。速度一般要比minor GC慢上10倍

a.引用计数法

现在主流的JVM无一使用引用计数方式来实现Java对象的自动内存管理,因为会存在“死锁现象”,本身维护需要消耗,而且较难处理循环引用

class CountGC {
    private byte[] bigSize = new byte[2 * 1024 * 1024];//这个成员属性唯一的作用就是占用一点内存
    Object instance = null;

    public static void main(String[] args) {
        CountGC objectA = new CountGC();
        CountGC objectB = new CountGC();
        objectA.instance = objectB;
        objectB.instance = objectA;
        objectA = null;
        objectB = null;
        System.gc(); //手动唤醒gc
    }
}

b.复制算法

优点:没有内存碎片,时间效率高
缺点:需要内存空间

主要发生在新生代,MinorGC采用

Eden:From:To = 8:1:1

New:Old=1:2堆空间

在这里插入图片描述

c.标记清除法

优点:不需要额外的内存空间
缺点:产生内存碎片、时间效率低

在这里插入图片描述

d.标记压缩法(标记整理法)

优点:不需要额外的内存空间,不会产生内存碎片
缺点:时间效率也不高

在这里插入图片描述

老年代GC:标记清除+标记压缩混合实现

多次标记清除+一次压缩 (Mark-Sweep-Compact)

总结

时间效率:复制>标记清除>标记压缩

内存碎片:复制算法=标记压缩>标记清除

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

更优算法:G1垃圾回收


有老哥评论指点:

首先非常感谢up,和视频的周阳老师,然后JVM 那块我补充一点点:
判断对象是否已经死亡的算法:引用计数算法,可达性分析算法;
四个垃圾收集算法:标记清除算法,复制算法,标记整理算法,分代收集算法;
七个垃圾收集器:Serial,SerialOld,ParNew,Parallel Scavenge,Parallel Old,CMS,G1.
视频中把引用技术算法归到垃圾收集算法了,以及没有提到可达性分析算法。还有就是垃圾收集器那块没有讲到。大家可以根据2,4,7这几个数字来差缺补漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值