JVM相关

1.JVM内存区域

一个运行起来的java进程就是一个Java虚拟机,就需要从操作系统中申请一大块内存。

内存中会根据作用的不同被划分成不同的区域:

(1)栈:存储的内容是代码在执行过程中,方法之间的调用关系(栈中每一个元素就是一个栈帧,代表一个方法的调用,包含方法的形参,返回值,局部变量)。

(2)堆:这里存储的内容是代码中new的对象

(3)方法区(1.8开始:元数据区):存储类对象(.class文件加载到内存就成为了类对象)

(4)程序计数器:存放每个线程,下一条指令执行的地址。空间较小主要就是用来存放一个“地址”,表示下一条要执行的指令,在内存的哪个地方(在方法区中去找下一条指令,指令是以二进制的形式存储在类对象中)。

程序计数器中的值会随着指令的执行,从而自动进行更新,去指向下一条指令。

如果是顺序执行的代码,那么下一条执行的指令地址就是把指令地址进行递增。

如果是条件循环执行的代码,那么下一条执行的指令地址就可能会跳到比较远的地址。

ps:栈和程序计数器每一个java线程一份,而堆和方法区是每一个java进程一份。(仅限java,放在c++中就不一定是这样了)

2.JVM类加载

(1)基本流程:

java代码经过编译后生成.class文件,java程序要想运行起来就需要将jvm读取这个.class文件,并且把里面的内容构造成类对象,保存到内存的方法区中。

官方文档中把类加载的过程分成了5个步骤:

1)加载:找到.class文件,并且打开文件,读取文件中的内容(通过全限定名称查找)

2)验证:检查当前二进制文件是否符合格式的要求,具体格式

3)准备:给类对象分配内存空间,并且为不被final修饰的static变量赋初始默认值(被final修饰的变量在此时会被赋值成程序员给定的值)

4)解析:针对类对象中字符串常量的处理,进行了一些初始化的操作。(符号引用到直接引用)

字符串常量在经过编译之后,eg:final String s = "hello",s本来是存储内存地址,但在.class文件中会重新针对该字符串进行创建出一个引用,此时这个引用就不是存储内存地址了,而是存储文件偏移量(字符串长度),通过这个变量就可以知道目前字符串处于哪个位置。到解析的阶段(类加载的时候),会重新将这个引用替换成内存地址。

5)初始化:对类对象中的各种属性进行初始化,还需执行静态代码块和加载一下父类(子类中调用构造方法,会先帮助父类进行构造)

(2)双亲委派模型:

是在加载过程中的第一个步骤。

首先需要了解一下类加载器

是JVM中的一个模块,JVM内置了三个类加载器:

1)BootStrap ClassLoader

2)Extension ClassLoader

3)Application ClassLoader

这三个类加载器之间的关系就好似爷父子之间的关系,但不是靠继承构成的,而是由类加载中的一个属性(parent)来指向父类加载器。

加载的具体流程是:

①根据给定的全限定类名,找到对应的.class文件。

②从Application ClassLoader作为入口,开始执行查找的逻辑。

③Application ClassLoader不会立即扫描自己所负责的目录(负责搜索项目当前目录和第三方库的对应目录),而是会交给自己的父类加载器Extension ClassLoader。

④Extension ClassLoader不会立即扫描自己所负责的目录(负责搜索JDK中一些扩展库对应的目录,是JDK标准库之外的一些库,属于对JDK标准库的扩展),而是会交给自己的父类加载器BootStrap ClassLoader。

⑤BootStrap ClassLoader,也不会立即扫描自己所负责的目录(负责搜索JDK标准库对应目录),而是会交给自己的父类加载器,但是却发现没有父类加载器,因此只能区扫描自己负责的目录,一旦在标准库中查找到对应类的.class文件,此时加载的过程就完了,扫描结束过后如果没有扫描到,就会交给它的子类加载器(Extension ClassLoader)扫描。

⑥如果在Extension ClassLoader扫描到了就结束加载过程,没有扫描到就交给它的子类加载器(Application ClassLoader)扫描。

⑦如果在Application ClassLoader扫描到了就结束加载过程,没有扫描到此时应该交给它的子类加载器扫描,但是发现没有了,所以此时会抛出一个异常ClassNotFoundException

总结:所谓的双亲委派模型其实就是一个按照优先级查找.class文件的一个过程,之所以有这么一套流程,是为了确保JDK标准库扫描的优先级最高,其次是扩展库,最后才是项目当前目录和引入的第三方库对应目录。就好比:你在自己的代码中使用String(导入的包是java.lang.String),在类加载的时候加载的JDK标准库中的类,而不是自己写的这个类。

 3.JVM垃圾回收机制(GC垃圾回收)

在java中new对象,是动态申请内存(运行时分配),如果一个资源申请了内存空间,长时间不使用但是不释放,就可能会造成内存泄漏。

在java中给出了一个方案,也就是垃圾回收机制,让JVM,自动判定某个内存是否不再使用了,

如果后面这个内存确实不用了,JVM就会自动回收把这个内存给回收掉了,此时就不需要手动回收了。

GC是垃圾回收,GC回收的目标是内存中的对象。对于java来说就是释放堆上的new出的对象,栈上的对象是随着栈帧的生命周期(方法执行结束,栈帧自然销毁,内存自然释放),静态变量,生命周期是整个程序,这个始终存在就意味着静态变量无需释放的,真正释放的就是堆上的对象。

GC回收垃圾的过程主要有两个步骤:

(1)找到垃圾

有两种主流的方案:

①引用计数

new出来的对象,会单独划分空间,来保存有一个计数器,计的是当前有多少引用指向该对象。

如果一个对象没有引用指向了(即引用计数为0),就可以将该对象视为垃圾了。

但是使用该种方式可能会存在两种问题:

·比较浪费内存:

计数器怎么说也得有两个字节,如果对象本身比较小,那么此时这个计数器所占空间比例就比较大了。

·存在循环引用问题:

②可达性分析:

有一组线程,周期性扫描代码中的所有对象,把所有可以访问到的对象,都给标记成“可达”,反之,如果经过扫描后,不可达的对象,就成垃圾了,需要被回收。

eg:

当然这里的遍历不一定是二叉搜索树,这里可达的实现大概率是靠N叉搜索树实现,这一步就是针对当前对象,看对象中有多少不同引用类型的成员,然后再对每一个类型的成员进行进一步的遍历。

通过上述过程,不难看出可达性分析是比较耗费资源的(开销较大)。 

(2)回收垃圾

有三种基本的回收思路:

①标记删除:

扫描到一个不可达的对象,就直接进行释放,这个方案非常不好,那就是会产生很多的内存碎片。释放代码,是为了让其他代码能够申请一块连续的内存空间,随着时间的推移,内存碎片的情况就会愈演愈烈,就会导致后续申请连续内存空间变得困难。

②复制算法:

通过复制的方式,把有效的对象,归类到一起,在同一释放剩下的对象。

也就是把内存一分为二,一次只用其中一半。但这种方式有两个明显的问题:

a.内存利用率不高

b.如果有效的对象很多,那么复制的开销将会很大

③标记整理:

既能解决内存碎片的问题,又能够解决上述内存利用率不高的问题。

eg:

类似于顺序表删除元素的搬运操作,使用该种方式搬运开销仍然很大。

而JVM中GC垃圾回收主要思想是分代回收(具体实现可能有一些调整和优化),是对上述思路的集合,让不同的方案,扬长避短。

分代回收有一个很重要机制就是:对象能活过的GC扫描轮次越多,就是越老(代表当前对象是暂时不会被释放的)

eg:下图是整个分代回收的全部过程:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git提交有乱码

服务器提交记录如图 可知application.properties中文注释拉黄线 ,提示Unsupported characters for the charset ISO-8859-1 打开settings - Editor - File Encodings 因为我们项目的其他文件都是UTF-8,所以,我们将默认值都改成UTF-8 然后…

OTA升级

方式1: 方式2: 服务器与mcu通讯机制

k8s的一些命令

kubectl get nodes :查看节点的状态 查看Pod的状态: kubectl get pod --all -namespacesPending,ContainerCreating,ImagePullBackOff都表明Pod没有就绪,Running才是就绪状态 查看Pod的具体情况: kubectl describe pod podnamek…

GEO数据库提取疾病样本和正常样本|GEO数据库区分疾病和正常样本|直接用|生物信息|生信

GEO数据库提取疾病样本和正常样本|GEO数据库区分疾病和正常样本|直接用|生物信息|生信 代码都可以直接用,修改GSE就可以! 通过代码查看数据的分类,是疾病还是正常样本 ##############################查看对饮GSE样本疾病or正常信息# 指定…

【机器学习】--- 自然语言推理(NLI)

引言 随着自然语言处理(NLP)的迅速发展,**自然语言推理(Natural Language Inference, NLI)**已成为一项重要的研究任务。它的目标是判断两个文本片段之间的逻辑关系。这一任务广泛应用于机器阅读理解、问答系统、对话…

图文讲解HarmonyOS应用发布流程

HarmonyOS应用的开发和发布过程可以分为以下几个步骤:证书生成、应用开发、应用签名和发布。 1. 证书生成: 在开始开发HarmonyOS应用之前,首先需要生成一个开发者证书。开发者证书用于标识应用的开发者身份并确保应用的安全性。可以通过Har…

渗透测试综合靶场 DC-1 通关详解

Vulnhub是一个提供各种漏洞环境的靶场平台,非常适合安全爱好者和渗透测试初学者进行学习和实践。在这个平台上,你可以下载多种虚拟机,这些虚拟机预装了各种漏洞,让你可以在本地环境中进行渗透测试、提权、漏洞利用和代码审计等操作…

nginx进阶篇(二)

文章目录 概图一、 Nginx服务器基础配置实例二、Nginx服务操作的问题三、Nginx配置成系统服务四、Nginx命令配置到系统环境五、Nginx静态资源部署5.1 Nginx静态资源概述5.2 Nginx静态资源的配置指令5.2.1. listen指令5.2.2. server_name指令配置方式匹配执行顺序 5.2.3 locatio…

【与C++的邂逅】--- C++的IO流

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: 与C的邂逅 本篇博客我们来了解C中io流的相关知识。 🏠 C语言输入输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 sc…

【C++】模拟实现vector

在上篇中我们已经了解过的vector各种接口的功能使用,接下来我们就试着模拟实现一下吧! 注意:我们在此实现的和C标准库中实现的有所不同,其目的主要是帮助大家大概理解底层原理。 我们模拟vector容器的大致框架是: t…

Java入门程序-HelloWorld

Java程序开发的三个步骤 1.编写代码得到 .java 源代码文件 2.使用javac编译得到 .class 字节码文件 3.使用java运行 注意事项 建议代码文件名全英文,首字母大写,满足驼峰命名法,源代码文件的后缀必须是.java 开发HelloWorld程序 &…

进程的属性

tips: task_struct就是linux下的PCB 操作系统不相信任何外部用户,而是只提供窗口,不可能直接与用户打交道,而是通过操作系统 tast_struct用来描述所有进程,用来管理 ; 和 && 可以同时跑两个命令 进…

AI修手有救了?在comfyui中使用Flux模型实现局部重绘案例

🐱‍🐉背景 局部重绘相关的话题我们已经讨论和测试过很多次了,比如说inpaint模型、brushnet模型、powerpaint模型等等,最近对于flux模型重绘画面的案例也越来越多了,那我们就结合flux模型的重绘来试试看效果。 &…

高级大数据开发协会

知识星球——高级大数据开发协会 协会内容: 教你参与开源项目提供新技术学习指导提供工作遇到的疑难问题技术支持参与大数据开源软件源码提升优化以互利共赢为原则,推动大数据技术发展探讨大数据职业发展和规划共享企业实际工作经验 感兴趣的私聊我,…

『功能项目』窗口可拖拽脚本【59】

本章项目成果展示 我们打开上一篇58第三职业弓弩的平A的项目, 本章要做的事情是给坐骑界面挂载一个脚本让其显示出来的时候可以进行拖拽 创建脚本:DraggableWindow.cs using UnityEngine; using UnityEngine.EventSystems; public class DraggableWindo…

linux网络编程2

24.9.18学习目录 一.数据包的传送1.数据包在每层间的传送2.链路层的封包3.网络层、传输层封包格式 二.字节序1.概念2.字节序转换函数 三.IP地址转换四.UDP1.概述2.网络编程接口socket3.UDP的C/S架构4.UDP编程 一.数据包的传送 1.数据包在每层间的传送 传送方数据从运用层到链…

MySQL之内置函数

目录 一:日期函数 二:字符串函数 三:数学函数 四:其他函数 一:日期函数 举例: (1) mysql> select current_date(); ---------------- | current_date() | ---------------- | 2024-09-17 | ---------------- 1 row …

# 利刃出鞘_Tomcat 核心原理解析(十一)-- Tomcat 附加功能 WebSocket -- 3

利刃出鞘_Tomcat 核心原理解析(十一)-- Tomcat 附加功能 WebSocket – 3 一、Tomcat专题 - WebSocket - 案例 - OnMessage分析 1、WebSocket DEMO 案例 实现流程分析:OnMessage 分析 2、在项目 dzs168_chat_room 中,在 websocke…

CSP-CCF★★★201903-2二十四点★★★

目录 一、问题描述 二、解答 方法一:穷举法(只列举了一部分) 方法二:中缀表达式直接求值,两个栈,一个存放数值,一个存放符号 方法三:将中缀表达式转换为后缀来计算注意&#xff…

SpringBoot2:web开发常用功能实现及原理解析-@ControllerAdvice实现全局异常统一处理

文章目录 前言1、工程包结构2、POM依赖3、Java代码 前言 本篇主要针对前后端分离的项目,做的一个统一响应包装、统一异常捕获处理。 在Spring里,我们可以使用ControllerAdvice来声明一些关于controller的全局性的东西,其用法主要有以下三点…