JVM 快速入门-B站【狂神说Java笔记】

狂神视频地址: https://www.bilibili.com/video/BV1iJ411d7jS

1. JVM的位置

在这里插入图片描述

2. JVM的体系结构

在这里插入图片描述
 JVM 调优百分之99都是在堆里面调优,方法区是特殊的堆。
在这里插入图片描述
在这里插入图片描述

3. 类加载器

  • 作用:加载Class 文件,~ new Student();
    • 类似模板,是抽象的
    • 对象是实现,是具体的
      在这里插入图片描述
      类是模板(抽象的),而对象是具体的
      在这里插入图片描述
  • 分类:
    • 虚拟机自带的加载器
    • 启动类(根)加载器
    • 扩展类加载器
    • 应用程序加载器

4. 双亲委派机制

// 双亲委派机制:安全
// APP–>EXC–>BOOT(最终执行)
// BOOT
// EXC
// APP

  • 第一步:类加载器收到类加载的请求
  • 第二步:将这个请求向上委托给父类加载器去完成 ,一直向上委托,直到启动类加载器(Boot)
  • 第三步:启动类加载器检查是否能够加载当前和这个类 ,能加载就结束,使用当前的加载器,否则,抛出异常,通知子加载器进行加载。
  • 第四步:重复 第三步 步骤。

null : java调用不到 ~ C 、C++
Java = C++ : 去掉繁琐的东西,指针,内存管理。(Java = C++ --)

5. 沙箱安全机制

参考:https://blog.csdn.net/qq_30336433/article/details/83268945

6. Native

凡是带了native 关键字的,说明java 的作用范围达不到了,会去调用底层C 语言的库。

  • 会进入本地方法栈。
  • 调用本地接口:JNI
    • JNI作用:扩展Java的使用,融合不同的编程语言为Java 所用!最初是想融合C、C++
    • Java诞生的时候,C和C++横行,要想立足,必须要有调用C/C++的程序。所以它在内存区域中专门开辟了一块标记区域:Native Method Stack,登记native 方法
    • 在最终执行的时候去加载本地方法库的方法,通过JNI

本地方法接口(JNI)Java Native Interface
本地方法库

private native void start0();

在这里插入图片描述
调用其他接口:Scoket 、WebService~…http

7. PC寄存器

程序计数器:Program Counter Register
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。

8. 方法区

Method Area 方法区

  • 方法区是被线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单说,所有定义的方法的信息都保存在该区域,此区域属于共享空间。
    静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是,实例变量存在堆内存中,和方法区无关
  • 方法区里面存以下内容
    static,final,Class 类模板,常量池
  • 类加载过程(面试
    new 一个类的时候,先在方法区有一个类的模板
    类模板完了 ,方法区还有个常量池
    引用在栈内存
    真实的 对象在堆内存
    引用指向堆内存真实的地址
    (参考Java基础)

9. 栈

栈:数据结构
程序 = 数据结构 +算法 : 持续学习~
程序 = 框架 + 业务逻辑 : 吃饭

栈:先进后出、后进先出
队列:先进先出(FIFO:First Input First Output)

  • 为什么main 方法 先执行,最后结束!
    栈:栈内存,主管程序的运行,生命周期与线程同步
    线程结束,栈内存也就释放,对于栈来说,不存在垃圾回收问题
  • 一旦线程结束,栈就over了

栈:8大基本类型+对象引用+实例的方法

栈运行原理:栈帧

程序正在执行的方法,一定在栈的顶部
在这里插入图片描述
栈 + 堆 + 方法区:的一些交互关系
在这里插入图片描述

  • 一个对象在内存中的实例化过程
public class People{
    String name; // 定义一个成员变量 name
    int age; // 成员变量 age
    Double height; // 成员变量 height
    void sing(){
        System.out.println("人的姓名:"+name);
        System.out.println("人的年龄:"+age);
        System.out.println("人的身高:"+height);
    }
    
    public static void main(String[] args) {
        String name; // 定义一个局部变量 name
    	int age; // 局部变量 age
    	Double height; // 局部变量 height
        
        People people = new People() ; //实例化对象people
        people.name = "张三" ;       //赋值
        people.age = 18;             //赋值
        people.stuid = 180.0 ;   //赋值
        people.sing();              //调用方法sing
    }
}

在这里插入图片描述
在程序的执行过程中,首先类中的成员变量和方法体会进入到方法区,如图:
在这里插入图片描述
程序执行到 main() 方法时,main()函数方法体会进入栈区,这一过程叫做进栈(压栈),定义了一个用于指向 Person 实例的变量 person。如图:
在这里插入图片描述
程序执行到 Person person = new Person(); 就会在堆内存开辟一块内存区间,用于存放 Person 实例对象,然后将成员变量和成员方法放在 new 实例中都是取成员变量&成员方法的地址值 如图:
在这里插入图片描述
接下来对 person 对象进行赋值, person.name = “小二” ; perison.age = 13; person.height= 180.0;

先在栈区找到 person,然后根据地址值找到 new Person() 进行赋值操作。

如图:
在这里插入图片描述
当程序走到 sing() 方法时,先到栈区找到 person这个引用变量,然后根据该地址值在堆内存中找到 new Person(),找到方法地址 进行方法调用。

在方法体void sing()被调用完成后,就会立刻马上从栈内弹出(出栈 )

最后,在main()函数完成后,main()函数也会出栈 如图:
在这里插入图片描述

10. 三种JVM

  1. Sun公司 HostSpot Java HotSpot™ 64-Bit Server VM (build 25.101-b13, mixed mode)
  2. BEA Jrockit
  3. IBM J9 VM

我们学习的都是HotSpot

11. 堆

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

  • 类加载器读取了类文件后,一般会把什么东西放到堆中?
    类的实例、方法、常量、变量~,保存我们所有引用类型的真实对象
  • 堆内存中还要细分为三个区域:
    • 新生区 (伊甸园区) Young/New
    • 养老区 old
    • 永久区 Perm
      在这里插入图片描述
  1. GC 垃圾回收主要是在伊甸园区和养老区~
  2. 假设内存满了,OOM ,堆内存不够!
  3. 在JDK 8以后,永久存储区改了个名字(元空间)

11.1 新生区

  • 类:诞生 和 成长的地方、甚至死亡。
  • 伊甸园区,所有的的对象都是在伊甸园区new 出来的!
  • 幸存者区(0,1)
    在这里插入图片描述
  • 假如伊甸园区满了,就触发一次轻GC,这次GC有以下情况:
    • 有的对象可以还被引用,就幸存下来了。
    • 有的对象没有被引用了,就死了、没了。
    • 幸存的下来的对象就移动到幸存区。
  • 当伊甸园区和幸存区都满了,就会触发一次重GC。
    • 重gc 清理一次后,能活下来的对象就进入养老区了。
      (就跟一场战争一样,不断的活下来)

真理:经过研究,99%的对象都是临时对象! new

11.2 永久区

  1. jdk 1.6之前:永久代,常量池是在方法区中
  2. jdk 1.7 :永久代,但是慢慢的退化了,去 永久代,常量池在堆中
  3. jdk 1.8 之后:无永久代,常量池在元空间

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

OOM出现条件:一个启动器,加载了大量的第三方jar包;Tomcat部署了太多应用,大量动态生成的反射类,不断被加载,直到内存满,就会出现OOM。
在这里插入图片描述
元空间:逻辑上存在,物理上不存在。

11.3 OOM排查

  • 在一个项目中,突然出现OOM 故障,那么该如何排除研究为什么出错
    • 能够看到代码第几行出错:内存快照分析工具,Eclipse MAT,Jprofiler
    • Debug,一行行分析代码~
  • MAT,Jprofiler作用:
    • 分析Dump内存文件,快速定位内存泄漏;
    • 获得堆中的数据
    • 获得大的对象~
  • 当出现OOM
    • 尝试扩大堆内存看结果
      -Xms1024m -Xmx1024m -XX:+PrintGCDetails
      在这里插入图片描述
      在这里插入图片描述
// -Xms1024m -Xmx1024m -XX:+PrintGCDetails
public static void main(String[] args) {
        // 返回虚拟机试图使用的最大内存
        long maxMemory = Runtime.getRuntime().maxMemory(); //字节 1024*1024

        // 返回JVM的总内存
        long totalMemory = Runtime.getRuntime().totalMemory();

        System.out.println("max="+maxMemory+"字节\t"+(maxMemory/(double)1024/1024)+"MB");
        System.out.println("total="+totalMemory+"字节\t"+(totalMemory/(double)1024/1024)+"MB");

        // 默认情况下,分配的总内存 是电脑内存的1/4,而初始化内存 是1/64
    }
 // -Xms8m -Xmx8m -XX:+PrintGCDetails
   public static void main(String[] args) {
       String str = "jdskanvkdfjhaljfnds";

       while (true) {
           str += str + new Random().nextInt(888888888) + new Random().nextInt(999999999);
       }
    }
  • 分析内存,看一下哪个地方出现了问题(专业工具)
    idea 安装Jprofiler
    。。。

12. GC 垃圾回收机制

垃圾回收的区域只有在堆里面(方法区在堆里面)
在这里插入图片描述
JVM 在进行垃圾回收(GC)时,并不是堆这三个区域统一回收。大部分时候,回收的都是新生代~

新生代
幸存区(form,to)
老年区

  • GC 两种类

    • 轻GC(普通GC):只针对 新生代 和 偶尔走一下 幸存区。
    • 重GC (全局GC): 全部清完。
  • 面试题目:

    • JVM的内存模型和分区~详细到每一个区放什么?
    • 堆里面的分区有哪些?
    • GC的算法有哪些?
      • 标记清除法
      • 标记整理
      • 复制算法
      • 引用计数法
      • 怎么用的?
    • 轻GC 和 重GC 分别再什么时候发生?

12.1 引用计数法

假设我对象A 用了 一次就给它加上1
假设我对象B 用了 两次就给它加上2
假设我对象C 没有使用 就是 0

引用计数法就是给每个对象分配一个计数器

假设C 对象为 0,它就要被清除出去了

JVM 现在一般不采用这种方式,不高效。
在这里插入图片描述
在这里插入图片描述

12.2 复制算法

每次GC 都会将 伊甸园区 活得对象 移动到 幸存区 中,如果幸存区放不下 ,就移到养老区中。
一旦伊甸园区被GC 后,就会是空的。
当某对象从伊甸园区 存活下来了。

谁空谁是to
假设这个对象还活着,它就把这个对象复制到另一个区域 要么是 form 要么是 to
当某个对象 经历15次(默认值)GC 都还没有死的时候,就会进入养老区。
在这里插入图片描述

  • 图解复制算法:
    • 假设 幸存区里面,to 是空的,form 里面有对象。
      在这里插入图片描述
    • 现在要做一次垃圾回收了
      首先:伊甸园区 存活的对象往 to 里面走
      在这里插入图片描述
      其次,form 区里面的 对象也要往 to 里面走
      在这里插入图片描述
      每次清理完之后,伊甸园区是空的,to区是空的。
      在这里插入图片描述
    • 经历15次GC之后,会把幸存区 里面或者的对象 移到养老区,或者有一些没有到15次就被清理掉
      在这里插入图片描述

好处:没有内存的碎片
坏事:浪费一半内存的空间:多了一半空间用于是空的。

复制算法最佳使用场景:对象存活度较低的时候;新生区

12.3 标记清除算法

扫描这些对象,对活着的对象进行标记
清除:对没有标记的对象,进行清除
在这里插入图片描述
优点:不需要额外的空间
缺点:两次扫描严重浪费时间,会产生内存碎片。

12.4 标记压缩

上面的再优化:防止内存碎片的产生(再次扫描,向一端移动存活的对象)
但是多了一个移动成本
在这里插入图片描述

12.5总结

内存效率:复制算法 > 标记清除算法 > 标记压缩算法(时间复杂度)
内存整齐度:复制算法 = 标记压缩算法 > 标记清除算法
内存利用率: 标记压缩算法 = 标记清除算法 > 复制算法

  • 没有最优算法吗?
    • 没有最好的算法,只有最合适的算法~ ---->GC: 分代收集算法
    • 每一代用合适的算法就好了。
  • 年轻代: (大部分的对象都在这里都死了)
    • 存活率低
    • 复制算法!
  • 老年代:
    • 存活率高,区域大
    • 标记清除 + 标记压缩 混合实现

JMM 新知识快速学习
1.
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值