JavaEE初阶学习:JVM(八股文)

news2024/11/25 4:47:16

1.JVM 中的内存区域划分

JVM 其实是一个Java进程~

java 进程会从操作系统这里申请一大块内存区域,给java代码使用~

内存区域进一步划分,给出不同的用途
1.堆 new 出来的对象 (成员变量)
2.栈 维护方法之间的调用关系 (局部变量)
3.方法区(旧) / 元数据区 (新) 放的是类加载之后的类对象~~ (静态变量)

这里的考点,主要就是给你一段代码,问你某个变量处于内存的哪个区域~~

看这个变量的形态~~(局部变量,成员变量,静态变量)
和这个变量的类型是无关的

在这里插入图片描述

虚拟机栈,是给 java 代码使用的
本地方法栈,是给 JVM 内部的本地方法使用的(JVM 内部通过C++代码实现的方法)

程序计数器,用途是记录当前程序指定到那个指令了~
简单的 long 类型的变量存了一个内存地址~
内存地址就是下一个要执行的 字节码 所在的地址~

堆和元数据区,在一个 JVM 进程中,只有一份
栈(本地方法栈和虚拟机栈)和程序计数器则是存在多份~
每个线程都有一份~

JVM 的线程和操作系统的线程是一对一的关系~~
每次在 java 代码中创建的线程,必然会在系统中有一个对应的线程~

2.JVM 的类加载机制

把 .class 文件加载到内存,得到类对象 这样的过程~
程序要想运行,就需要把依赖的"指令和数据"加载到内存中

类加载的步骤非常复杂,我们把他总结成5个词~

1.类加载过程

1.加载

找到 .class 文件,并且读文件内容
找到过程涉及到一个经典的考点,双亲委派模型~

2.验证

.class 文件有明确的数据格式(二进制的)

在这里插入图片描述

3.准备

给类对象分配内存空间(未初始化的空间,内存空间中的数据是全0的)
类对象中的静态成员也是全0的

类加载,最终就是为了得到类对象~

4.解析

针对字符串常量进行初始化~

将常量池内的符号引用替换为直接引用的过程

字符串常量在 .class 文件中就存在了,但是它们只是知道彼此之间的相对位置(偏移量),不知道自己在内存中的实际地址,这个时候的字符串常量就是符号引用~

真正加载到内存中,就会把字符串常量填充到内存中的特定地址上.
字符串常量之间的相对位置还是一致的,但是这些字符串有了自己真正的内存地址

此时的字符串就是直接引用(java 中的普通的引用)

5.初始化

针对类对象进行初始化(初始化静态成员,执行静态代码块,类要是有父类还需要加载父类)


类加载这个动作,什么时候会触发?
不是JVM一启动,就把所有的 .class 都加载了!! 整体是一个"懒加载"的策略(懒汉模式)
非必要,不加载~

什么叫做"必要"
1.创建了这个类的实例
2.使用了这个类的静态方法/静态属性
3.使用子类,会触发父类的加载~

2.双亲委派模型

做的工作,就是在加载中,找 .class 文件这个过程~

在 JVM 中,加载类,需要用到一组特殊的模块,类加载器~~

在 JVM 中,内置了三个 类加载器~
BootStrap ClassLoader —> 负责加载 java 标准库中的类
Extension ClassLoader —> 负责加载一些非标准的但是Sun / Oracle 扩展的库的类
Application ClassLoader —> 负责加载项目中自己写的类以及第三方库中的类~

当具体加载一个类的时候,过程是这样的~
需要先给定一个类的全限定类名 “java.lang.String”(字符串)

在这里插入图片描述

BootStrap 没有父亲类加载器了,因此就直接只能自己来搜索自己负责的片区~如果搜索到,就直接后续加载步骤,如果没搜索到,再交给孩子来处理

Extension 收到了父亲的反馈,自己来找~~
如果搜索自己负责的片区,找到了,直接进行后续加载步骤~
如果没搜索到,再交给孩子处理~

Application 收到了父亲的反馈,自己来找~~
如果搜索自己负责的片区,找到了,直接进行后续加载步骤~
如果没搜索到,也是交给孩子处理~
没有孩子了,就抛出一个 ClassNotFoundExeception

3.JVM 中的垃圾回收策略

帮助程序员自动释放内存

C语言中,malloc 的内存必须手动free,否则就容易出现内存泄漏~

java等后续的编程语言,引入了GC来解决上述问题~
能够有效的减少内存泄露的出现概率!

c/c++ 做法是完全让程序员来决定~
比较不靠谱,特别依赖程序员的水平~

java 通过 JVM 自动判定~~ 基于一系列的策略
就可以让这个准确性比较高~但是也会付出一些代价

JVM 中的内存有好几个区域,是释放哪个部分的空间呢?
堆!!!(new 出来的对象)

程序计数器,就是一个单纯存地址的整数,不需要~~随着线程一起销毁.
栈,也是随着线程一起销毁,方法调用完毕,方法的局部变量自然随着出栈操作就销毁了~
元数据区 / 方法区,存的类对象,很少会"卸载"

堆!!! GC的主要目标~
GC 也就是以对象为单位进行释放的~~(说是释放内存,其实是释放对象)

GC 中主要分成两个阶段:

1. 找,谁是垃圾

找的过程就涉及到垃圾回收算法~(基本的思想方法,不代表真实的实现方法)

一个对象,如果后续再也不用了,就可以认为是垃圾!!

如果一个对象,没有引用指向他,此时这个对象一定是无法被使用的()
如果一个对象已经不想用了,但是这个引用可能还指向着~~

java 中只是单纯通过引用没有指向这个操作,来判定垃圾的~
java对于垃圾对象的识别是比较保守的~最大程度避免误杀!!

具体来说,java 怎样知道一个对象是否有引用指向呢?

1.引用计数 给对象里安排一个额外的空间,保存一个整数,表示该对象有几个引用指向~(Python,PHP)

给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已"死"

存在的缺陷:
1.浪费内存空间~~
2.存在循环引用的情况!!(会导致引用计数的判定逻辑出错)

2.可达性分析 把对象之间的引用关系,理解成了一个树形结构.从一些特殊的起点出发,进行遍历.只要能遍历访问到的对象,就是"可达".再把"不可达的"当做垃圾即可~
(java)

可达性分析的关键要点,进行上述遍历,需要有"起点"~~
1.栈上的局部变量(每个栈的每个局部变量,都是起点)
2.常量池中引用的对象
3.方法区中,静态成员引用的对象~

可达性分析,总的来说,就是从所有的 gcroots 的起点出发.看看该对象里又通过引用能访问哪些对象,顺藤摸瓜的,把所有可以访问的对象都给遍历一遍(遍历的同时把对象标记为"可达")

剩下的自然就是"不可达"的.

可达性分析自己的缺点:
1.消耗更多的时间~~ 某个对象成了垃圾,也不一定能第一时间发现,因为扫描的过程,需要消耗时间
2.在进行可达性分析的时候,要顺藤摸瓜,一旦这个过程中,当前代码中的对象的引用关系发生变化了,就麻烦了~
因此,为了更准确的完成这个"摸瓜"的过程,需要让其他的业务线程暂停工作!!(STW问题)

2. 释放~~ 把垃圾对象的内存给释放掉

三种典型的策略
1.标记整理

在这里插入图片描述

直接把垃圾对象的内存进行释放
这种方式会产生内存碎片!!(申请的空间都是申请的"整块的连续空间",现在这里空闲的空间是离散的,独立的空间,)

2.复制算法
把整个内存空间,分成两段~~
一次只用一半~

在这里插入图片描述

复制算法,就把不是垃圾的对象.拷贝到另外一边.
然后再统一释放整个区域!!

在这里插入图片描述

复制算法,解决了内存碎片的问题,也有缺点!!
1.内存利用率比较低!
2.如果当前的对象大部分都是要保留的,垃圾很少,此时复制成本就比较高~

3.标记整理

在这里插入图片描述

类似于顺序表删除中间元素,有一个搬运过程~

在这里插入图片描述

1.解决了内存碎片问题
2.但是搬运的开销也比较大

因此,实际的 JVM 的实现思路,是结合了上述几种思想方式~

分代回收思想

分代算法和上面讲的 3 种算法不同,分代算法是通过区域划分,实现不同区域和不同的垃圾回收策略,从而实现更好的垃圾回收

给对象设定了"年龄"这样的概念~描述了这个对象存在多久了.
如果一个对象刚诞生,认为是0岁
每次经过一轮扫描(可达性分析),没被标记成垃圾,这个时候对象就长一岁!
通过对象来区分这个对象的存活时间~

针对不同年龄的对象采取不同的回收策略~

在这里插入图片描述

1.新创建的对象,放到伊甸区.
当垃圾回收扫描到伊甸区之后,绝大部分对象都会在第一轮gc 中就被干掉~~大部分对象是活不过一岁的(经验规律)
朝生夕死~

2.如果伊甸区的对象,熬过第一轮GC,就会通过复制算法,拷贝到生存区~~

生存区分成两半(大小均等),一次只使用其中一半~

垃圾回收扫描伊甸区的对象,也是发现垃圾就淘汰,不是垃圾的,通过复制算法,复制到生存区的另外一半 ~

3.当这个对象在生存区,熬过若干轮gc之后,年龄增长到一定程度了,就会通过复制算法拷贝到老年代(多年的媳妇熬成婆了)

4.进入老年代的对象,年龄都挺大了,再消亡的概率比前面新生代中的对象小不少,针对老年代的gc 的扫描频次就会降低很多

如果老年代中发现某个对象是垃圾了,使用标记整理的方式清除~~

5.特殊情况:如果对象非常大,直接进入老年代(大对象进行复制算法,成本比较高,而且大对象也不会很多.…)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1194552.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

K8S容器持续Terminating无法正常关闭(sider-car容器异常,微服务容器正常)

问题 K8S上出现大量持续terminating的Pod,无法通过常规命令删除。需要编写脚本批量强制删除持续temminating的Pod:contribution-xxxxxxx。 解决 获取terminating状态的pod名称的命令: # 获取media命名空间下,名称带contributi…

【论文解读】针对生成任务的多模态图学习

一、简要介绍 多模态学习结合了多种数据模式,拓宽了模型可以利用的数据的类型和复杂性:例如,从纯文本到图像映射对。大多数多模态学习算法专注于建模来自两种模式的简单的一对一数据对,如图像-标题对,或音频文本对。然…

Ubuntu系统使用apt-get管理软件工具

记录一下使用Ubuntu系统的apt-get管理软件工具 先查看一下系统的版本,可以看到这里使用的是Ubuntu20.04版本,版本代号focal rootmyw:~# uname -a Linux myw 5.4.0-70-generic #78-Ubuntu SMP Fri Mar 19 13:29:52 UTC 2021 x86_64 x86_64 x86_64 GNU/L…

NI USRP软件无线设备的特点

NI USRP软件无线设备 NI的USRP(Universal Software Radio Peripheral)设备是RF应用中使用的软件无线(SDR)。NI的USRP收发器可以在多个频段发送和接收RF信号,因此可用于通信工程教育和研究。通过与LabVIEW开发环境相结合,USRP可以实现使用无线信号验证无…

在gitlab中的使用kaniko打造流水线

文章目录 kaniko工具介绍环境说明系统版本组件版本组件部署参考链接 部署harbor下载解压、创建相关目录配置部署 gitlab集成harbor集成项目ci配置最终结果 kaniko工具介绍 kaniko 是一种从容器或 Kubernetes 集群内的 Dockerfile 构建容器镜像的工具。 kaniko 解决了使用 Doc…

云效流水线docker部署 :node.js镜像部署VUE项目

文章目录 引言I 流水线配置1.1 项目dockerfile1.2 Node.js 镜像构建1.3 docker 部署引言 云效流水线配置实现docker 部署微服务项目:https://blog.csdn.net/z929118967/article/details/133687120?spm=1001.2014.3001.5501 配置dockerfile-> 镜像构建->docker部署。 …

GEE:将鼠标变成十字指针,点击获取影像值,显示值到UI中

作者:CSDN @ _养乐多_ 本文记录了在 Google Earth Engine(GEE)开发中,将鼠标变成十字指针,点击获取影像值,显示值到UI中的代码片段。这段代码复制过去修改变量名就可以用了。 效果如下图所示, 文章目录 一、代码片段一、代码片段 使用的时候将 YLDImage 变量换成你屏…

C++结构体定义 创建 赋值 结构体数组 结构体指针 结构体嵌套结构体

结构体是什么&#xff1f; struct是自定义数据类型&#xff0c;是一些类型集合组成的一个类型。结构体的定义方式 #include<iostream> using namespace std;struct Student {string name;int age;int score; };创建结构体变量并赋值 方式一&#xff0c;先创建结构体变…

汽车标定技术(九)--标定常量与#pragma的趣事

目录 1. 不添加#pragma语句 2. 添加#pragma语句 3. 标定量只给flash空间&#xff0c;不给ram指定空间 4. 总结 在之前不会使用overlay机制的时候&#xff0c;我们想要做汽车标定&#xff0c;标定常量编译出来的地址一般都应该是ram的地址&#xff0c;而且在链接文件中都会指…

Django——orm模块创建表关系

django orm中如何创建表关系 1. 表关系分析 表与表之间的关系: 一对多 多对多 一对一 没有关系 判断表关系的方法: 换位思考用4张表举例: 图书表 出版社表 作者表 作者详情表图书和出版社是一对多的关系 外键字段建在多的那一方图书和作者是多对多的关系 需要创建第三张表来…

企业年会/年终活动如何邀请媒体记者报道?

​媒体邀约是企业或组织进行宣传的重要手段之一。通过邀请媒体参加活动&#xff0c;可以增加活动的曝光度和知名度&#xff0c;吸引更多的关注和参与。同时&#xff0c;媒体报道还可以提高企业或组织的权威性和可信度&#xff0c;从而让公众更容易接受其传达的信息。 企业年会或…

比较PID控制和神经网络控制在机器人臂上的应用

机器人臂是自动化领域中常见的机器人形式&#xff0c;其精确控制对于实现复杂任务具有重要意义。在机器人臂的控制中&#xff0c;PID控制和神经网络控制是两种常用的控制方法。本文将比较PID控制和神经网络控制在机器人臂控制方面的应用&#xff0c;包括控制原理、优缺点以及在…

Linux 多线程控制详解

目录 多线程编临界资源访问 互斥锁 API 简述 初始化互斥量 互斥量加锁/解锁 互斥量加锁(非阻塞方式) 互斥量销毁 程序示例 多线程编执行顺序控制 信号量 API 简述 初始化信号量 信号量 P/V 操作 信号量申请(非阻塞方式) 信号量销毁 程序示例 条件变量 创建和销毁…

分享一个JavaScript后台管理项目超实用的提示框

目录 新建js文件 设置css样式 html布局 script代码 调用方式 展示效果 新建js文件 首先我们需要新建一个js文件夹&#xff0c;将下方代码丢进去 "use strict";function _typeof(obj) { "babel/helpers - typeof"; if (typeof Symbol "f…

C/C++输出硬币翻转 2021年6月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C硬币翻转 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C硬币翻转 2021年6月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 假设有N个硬币(N为不大于5000的正整数)&#xff0c;从1…

【Linux】tree命令的独特用法

有关tree命令&#xff0c;我们只知道它可以将文件目录以树状图的形式展示&#xff0c;但其实还有很多有意思的功能可以使用。 一、tree命令的安装 各linux版本不同&#xff0c;但软件包名字就叫tree&#xff0c;直接安装即可 ubuntu&#xff1a; apt install tree centos&a…

rust实现quic服务端和客户端

演示如何使用 Quinn 库实现一个简单的 QUIC 客户端和服务器。QUIC 是一种基于 UDP 的协议&#xff0c;用于在互联网上进行快速和安全的通信。 在程序中&#xff0c;使用了 Rust 的标准库中的 error、net 和 sync 模块&#xff0c;以及第三方库 tokio 和 quinn。程序使用了 asy…

智慧畜牧小程序开发流程

本文将详细介绍智慧畜牧小程序的开发流程&#xff0c;包括需求分析、设计、开发、测试和上线等环节。同时&#xff0c;将深入思考智慧畜牧小程序的发展趋势和未来挑战&#xff0c;为读者提供有深度的思考和逻辑性的分析。 一、需求分析 1.明确目标用户&#xff1a;首先…

tomcat+idea--如何在idea上发布项目

对应于idea2022以后的版本 &#xff08;一&#xff09;如何配置idea上的tomcat&#xff1f; 1、新建一个项目&#xff0c;左上角File&#xff0c;new&#xff0c;project&#xff0c;新建后就和普通的java项目一样。 2、然后点击项目名&#xff0c;右键选择“Add framework s…

Node.js中的child_process模块的作用

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…