• JavaEE初阶---JVM


    在这里插入图片描述

    一 : JVM简介

    JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机 .

    虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。

    常见的虚拟机:JVM、VMwave、Virtual Box .

    JVM 和其他两个虚拟机的区别:

    1. VMwave与VirtualBox是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器;
    2. JVM则是通过软件模拟Java字节码的指令集,JVM中只是主要保留了PC寄存器,其他的寄存器都进
      行了裁剪 .

    JVM 是一台被定制过的现实当中不存在的计算机 .

    不管是现在仍在广泛使用JDK6,还是使用比较多的JDK8中,默认的虚拟机都是HotSpot;Sun/Oracle JDK和OpenJDK的默认虚拟机。从服务器、桌面到移动端、嵌入式都有应用。

    我们主要会介绍有关JVM的以下三方面内容 :

    在这里插入图片描述

    二 : JVM内存区域划分

    java进程启动的时候 , 就会从操作系统这里申请来一大块内存 , 进行装修 , 会把场地划分成多个区域 , 每个区域又有不同的功能 !
    
    • 1

    在这里插入图片描述

    2.1 堆

    堆的作用:程序中创建的所有对象都在保存在堆中.堆是最重要的区域,也是占地面积最大的区域.
    
    • 1

    2.2 栈

    在这里插入图片描述

    2.3 方法区

    用来存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据.
    
    • 1

    在这里插入图片描述
    误区辨析 :

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

    2.4 程序计数器

    占地最小的区域,只是单纯保存当前代码执行到哪个指令了(存储下一个要执行的指令地址).
    
    • 1

    写好的代码 , 是被加载到内存里的 , 既然在内存里 , 每个指令都有对应的"地址" , 程序计数器就记录了当前执行到哪条指令了 , 相当于一个"书签" .

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

    开发中可能会遇到这样的问题 :

    1. StackOverflowException , 栈溢出 , 检查是否是方法调用层数太多了 , 尤其是出现了"无限递归" .
    2. OutMemoryException , 堆溢出 , 检查是否是new的对象太多了 , 比如反复new对象并插入一个List里面 , 对象越积越多 , 就会把堆给撑满 !

    三 : 类加载

    编译生成的.class文件在硬盘里,Java进程启动(JVM启动),需要把.class文件从硬盘读到内存中,并构造出类对象,这就是类加载.
    
    • 1

    在这里插入图片描述
    Java Language and Virtual Machine Specifications文档中的这个章节 , 就详细介绍了.class文件的格式 :

    在这里插入图片描述

    双亲委派模型

    类加载中最典型的面试题:双亲委派模型,描述的是类加载中的"加载阶段",去那些目录里找.class文件.
    
    • 1

    类加载器是JVM中特殊的模块,功能就是负责把类加载起来(完成类加载的工作) .

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    如果这一圈下来都没找到 , 就会抛出ClassNotFoundException !

    为什么要按照这个双亲委派模型的规则来进行工作呢 ? 目的就是为了防止程序猿自己写了一个特殊的类 , 把标准库里的类给覆盖了 . 那么 , 如果自己写个类加载器器 , 是否仍然要遵守双亲委派模型呢 ? 答案是可以遵守 , 也可以不遵守 , 如Tomcat里加载一些webapps里的类时就有自己的类加载器 , 且并未遵守双亲委派模型 .

    四 : 垃圾回收机制

    为什么需要GC?

    在C语言中, malloc动态申请内存 , 除非手动释放 , 否则就要等到程序结束时才会释放 . 在C中 , 内存释放全靠程序猿手动来保证 , 这是极其不靠谱的 . 合适的做法 , 是让机器自动保证 , 由机器自动负责回收不再使用的内存 , 这件事就是"垃圾回收机制" , 即GC .(garbage collection) .

    那些内存才需要被回收呢 ?

    1. 程序计数器不需要 , 这个空间是固定的 , 跟随线程一起销毁即可 ;
    2. 栈不需要,栈这里主要就是局部变量,约定了变量出了作用域,就可以回收了.
    3. 方法区,放的是类对象,主要任务是"类加载" , 很少会涉及到"类卸载" , 也就很少涉及到GC ;
    4. 堆需要 , 放的是new出来的对象 , 用完之后 , 就需要被清理 , 此时就是GC的主战场了 .

    注意 : 垃圾回收的基本单位是"对象" , 不是"字节" .

    在这里插入图片描述

    如何确定一个对象是不是垃圾呢 ?

    在这里插入图片描述

    1.引用计数

    就是使用额外的计数器,记录某个对象,有多少个引用指向它.
    
    • 1

    在这里插入图片描述
    可以把对象想象成 , 小旅馆的一个房间 . 引用就是房间的房卡 . 如果客人手里有房卡 , 则房间是正在使用的状态 , 如果客人手里没有房卡 , 则房间就应该被回收了 .

    这个方案确实可以解决问题 , 但是也有缺陷 :

    在这里插入图片描述
    正由于这些缺陷 , java中没有采用这种方式 , 而是使用了"可达性分析" .

    2.可达性分析

    以代码中一些特殊的变量作为起点 , 然后从起点出发 ,  看看那些对象能够被访问到 , 如果对象被访问到了 , 就标记成"可达" . 当完成一圈标记之后 , 剩下的就是"不可达" , 也就是"垃圾"了 .
    
    • 1

    什么样的变量可以被称为"起点"呢 ?

    GCRoot :

    1. 局部变量表中的引用(栈里面的局部变量) , 栈有多个 , 每个线程一个 , 每个栈里又有很多栈帧 , 每个栈帧有一个自己的"局部变量表" . 所有线程的所有栈的所有局部变量表中的所有变量 , 都视为GCRoot .
    2. 常量池中对应的对象 ;
    3. 方法区中 , 静态引用类型的成员 .

    优势 : 可达性分析相比于引用计数来说 , 不会占用额外的内存空间 ; 也不会涉及到循环引用的问题 .

    具体的垃圾回收算法

    1.标记-清除

    在这里插入图片描述

    2.复制算法

    在这里插入图片描述

    3.标记-整理

    在这里插入图片描述

    4.分代回收

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

    在这里插入图片描述

    这里涉及到几个经验规律 :

    1. 伊甸区中的对象绝大多数活不过一轮GC ;
    2. 如果一个对象生命周期比较短 , 很快就没了 ; 如果一个对象经历了几轮GC还没事 , 大概率其生命周期就很长了 .

    一个小例外 : 如果当前有一个特别大的对象 , 不经历上述分代过程 , 直接进入老年代!!!因为大对象在复制算法中是很不友好的 .

    以上就是四种基本的垃圾回收 . 算法实际上JVM具体是通过"垃圾回收器"来实现的上述算法 , 不同的垃圾回收器,其实针对上述算法的实现,还有一些具体的差异 . 面试中主要考的是垃圾回收算法,而不是回收器 !

    本节内容到此结束 !!!

  • 相关阅读:
    七、装饰者模式
    索引和切片--numpy
    React - 01
    MySQL索引
    SpringCloud链路追踪——Spring Cloud Sleuth 和 Zipkin 介绍 & Windows 下使用初步
    【luogu CF487E】Tourists(圆方树)(树链剖分)(线段树)
    还是分不清非阻塞赋值与阻塞赋值吗?
    Redis Desktop Manager安装和使用
    深度学习读取txt训练数据绘制参数曲线图的方法
    供应链金融融资模式
  • 原文地址:https://blog.csdn.net/baijaiyu/article/details/127809079