当前位置: 首页 > news >正文

【JavaEE 初阶(十)】JVM

❣博主主页: 33的博客❣
▶️文章专栏分类:JavaEE◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你了解更多进阶知识

在这里插入图片描述

目录

  • 1.前言
  • 2.JVM内存区域划分
  • 3.类加载
    • 3.1双亲委派模型
  • 4.垃圾回收(GC)
    • 4.1垃圾识别
      • 4.1.1引用计数
    • 4.1.2可达性分析
    • 4.2垃圾释放
    • 4.2.1标记释放
    • 4.2.2复制算法
    • 4.2.3标记整理
    • 4.2.4分代回收
  • 5.总结

1.前言

JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统,JVM本省是一个比较复杂的东西,我主要从三个方面进行讲述:内存区域划分,类加载机制垃圾回收算法。

2.JVM内存区域划分

JVM其实就是一个进程,进程在运行过程中,要从操作系统申请资源空间,JVM申请的空间会划分为几个不同的区域,每个区域作用各不相同。这些资源支持了后续Java程序的执行。
在这里插入图片描述
堆区:整个进程只有一份,代码中new出来的对象,对象中的非静态成员变量,放在堆区
栈区:虚拟机栈记录了JAVA代码中的调用关系,java局部变量。
程序计数器:专门用来存储下一条Java指令的地址
元数据:整个进程只有一份,一些辅助性质的,描述性质的属性,我们所写的JAVA代码,各种逻辑运算,会通过javac完成代码转换成字节码,此时这些字节码在程序运行时就会被JVM加载到元数据中,此时当前程序如何执行,做哪些事就按照上述元数据区记录的字节执行。
下列元素n,m,t各在什么区?

class Test{
int n;
static int m;
}
main(){
Test t=new Test();
}

t为局部变量在栈区
new Test在堆区
n是成员变量也在堆中
m是static修饰,类属性在元数据区

3.类加载

类加载就是指JAVA程序运行是,把.class文件从硬盘中读到内存,再进行一系列解析。
类加载大致可以分为5步:
1)加载
把硬盘上的.class文件找到,打开文件读取文件内容
2)验证
确保读到的文件内容是合法的
3)准备
给类申请内存空间,默认值为全0
4)解析
主要针对类中的字符串常量进行处理
例如有一串代码为String s=”hello";s变量存入的是hello的地址,但是再.calss文件中不纯在地址的概率,那么为了就可以给s填一个偏移量。
在这里插入图片描述

5)初始化
把类对象的各个部分的属性进行赋值填充

3.1双亲委派模型

在类加载的时候有一个重要模型就是双亲委派模型,描述了如何找到.class文件。在进行加载操作的时候有一个专门的模块叫做类加载器,默认含有三个
BootstrapClassLoader:负责查找标准库的目录
ExtensionClassLoader:负责查找扩展库的目录
ApplicationClassLoader:负责查找当前项目的代码目录,第三方库目录
上述三个类加载器存在父子关系,类似于二叉树,有一个指针指向父类加载器
在这里插入图片描述
双亲委派工作流程:
1)从ApplicationClassLoader作为入口,开始工作
2)ApplicationClassLoader不会立即搜索自己负责的目录,会把搜索的任务交给自己的父亲
3)进入ExtensionClassLoader,也不会立即搜索自己负责的目录,也会把搜索的任务交给自己的父亲
4)进入BootstrapClassLoader,不会立即搜索自己负责的目录,也会把搜索的任务交给自己的父亲
5)BootstrapClassLoader发现自己没有父亲节点,此时会真正的搜索负责的目录,如果找到了就执行后续操作,没有找到就返回给孩子
6)ExtensionClassLoader收到父亲的任务以后,会搜索自己负责的目录,如果找到了就执行后续操作,没有找到就返回给孩子
7)ApplicationClassLoader收到父亲的任务以后,会搜索自己负责的目录,如果找到了就执行后续操作,没有找到就返回给孩子,但如果没有孩子就说明类加载失败,抛出ClassNotFoundException

4.垃圾回收(GC)

垃圾回收是回收的内存,其中主要回收的是堆中的内存,栈中的内存在代码块结束以后会自动销毁。那么垃圾回收具体是怎么展开的呢?主要分为垃圾识别和垃圾释放

4.1垃圾识别

判定new出来的对象在后续是否要使用,如果不再使用旧标记为垃圾。
例:

void func(){
Test t=new Test();
t.find();
}

当程序执行到}时,t就被释放,此后就不再使用new Test()对象了,就可以标记为垃圾,但如果有些大妈比较复杂,例如

Test t=new Test();
Test m=t;
Test n=m;
Test z=n;

此时就有很多引用指向new Test()对象,就学要确保没有任何一个引用指向这个对象才能标记为垃圾,那么我们怎么知道什么时候没有引用指向它呢?

4.1.1引用计数

当我们创建一个对象时,给每个对象分配一个额外的空间记录当前对象有几个引用。
在这里插入图片描述
每增加一个引用,计数位置+1,每减少一个引用,技术位置-1,如果为0就标记为垃圾
问题一
这样会消耗额外的空间,当我们的对象非常多,但对象的体积非常小,那么久可能导致计数所占的空间就占了所有空间的大部分。
问题二
可能会引起循环引用,那么就永远释放不了资源

class Test{
Test t;
}
Test a=new Test();
Test b=new Test();
a.t=b;
b.t=a;
a=null;
b=null;

在这里插入图片描述
这俩对象不能再使用也释放不了

4.1.2可达性分析

在写代码的时候会定义很多变量,就可以从这些变量作为起点开始遍历,所谓的遍历就是会沿着这些变量的引用类型成员再京一部访问,所有能被访问到的自然不是垃圾
在这里插入图片描述

4.2垃圾释放

4.2.1标记释放

最直接的方法就是把标记为垃圾的直接释放掉:但是这样会生成很多内存碎片,后续如果有类对象再申请空间可能就不够用
在这里插入图片描述

4.2.2复制算法

把一个空间分成两半,假设数据存放于左半边那么把不是垃圾的数据全部赋值到右半再讲左半数据全部释放掉。
灰色为垃圾标记,数字为数据
在这里插入图片描述
在这里插入图片描述
这样总的内存空间减少,且复制的开销也很大。

4.2.3标记整理

在这里插入图片描述
在这里插入图片描述
该方案是把所有的数据依次向前搬运,覆盖掉垃圾区,再把剩下的垃圾进行释放。
虽然这样能解决内存碎片的问题,但搬运的内存开销很大

4.2.4分代回收

JVM中有专门的线程负责周期性扫描,一个对象如果被扫描了一次,年龄就+1,JVM会根据对象年龄的差异,把整个堆分成2部分,新生代,老年代。
在这里插入图片描述
1)当代码中new出一个新的对象,这个对象就是被创建在伊甸区,伊甸区的对象大部分都活不够第一轮,生命周期非常短
2)第一轮GC扫描完成以后,少数伊甸区幸存的对象会通过复制算法拷贝到生存区,在后续GC扫描的时候不仅会扫描伊甸区还会扫描生存区的对象,生存区的大多数对象也会在扫描中被标记为垃圾,少数存活,就会继续通过复制算法拷贝到另一个生存区,每次经历一轮GC年龄就+1.
3)如果这个对象在生存区中经历了若干轮依然在,那么就会把这个对象拷贝到老年区。
4)老年代的对象也会被GC扫描只是频次大大减小
5)对象在老年代结束以后就会释放内存。

5.总结

本篇文章主要JVM内存区域划分,类加载,双亲委派模型,垃圾识别,引用计数,可达性分析,垃圾释放,分代回收等等。

下期预告:MySQL

相关文章:

  • 【秒杀系统】从零开始打造简易秒杀系统(一):防止超卖
  • mysql实战——xtrabackup全量备份/增量备份及恢复
  • 机械产品3d模型网站让您的展示内容更加易于分享和传播
  • 大模型基础知识
  • 记录一次安装k8s初始化失败
  • 介绍下 npm 模块安装机制,为什么输入 npm install 就可以自动安装对应的模块
  • Docker 入门版
  • jdk8中元空间是否会触发GC
  • GitLab的原理及应用详解(四)
  • 打造坦克游戏:类方法的深入解析
  • 【ARMv7-A】——ATPCS(ARM-Thumb 过程调用标准)
  • 邦注科技三机一体除湿干燥机在工业中的应用
  • 达梦数据库登报测评命令
  • 适合下班做的副业兼职、1天挣300,7天涨粉2万
  • HTML5和CSS3的新特性
  • django开发-定时任务的使用
  • gitlab-ci配置详解(一)
  • Javascript Math对象和Date对象常用方法详解
  • JavaScript设计模式与开发实践系列之策略模式
  • JavaScript中的对象个人分享
  • laravel5.5 视图共享数据
  • Leetcode 27 Remove Element
  • MySQL几个简单SQL的优化
  • Python连接Oracle
  • TCP拥塞控制
  • Vue.js-Day01
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • Web设计流程优化:网页效果图设计新思路
  • windows-nginx-https-本地配置
  • 闭包--闭包之tab栏切换(四)
  • 基于webpack 的 vue 多页架构
  • 记一次用 NodeJs 实现模拟登录的思路
  • 一个JAVA程序员成长之路分享
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • !$boo在php中什么意思,php前戏
  • #### go map 底层结构 ####
  • #565. 查找之大编号
  • #NOIP 2014#Day.2 T3 解方程
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • $ git push -u origin master 推送到远程库出错
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (33)STM32——485实验笔记
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)EOS中账户、钱包和密钥的关系
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能