浅谈 JVM
JVM 内存划分
JVM 内存划分为 四个区域,分别为 程序计数器、元数据区、栈、堆
程序计数器是记录当前指令执行到哪个地址
元数据区存储存储的是当前类加载好的数据,包括常量池和类对象的信息,.java 编译之后产生 .class 文件,运行代码的时候会把了类对象的信息保存在内存里,其中类元信息包括:类名、类的父类,实现哪些接口,类的权限public/private…
方法元信息:方法名,参数类型,返回值…
类元信息和方法元信息都是类对象里面包含的。
栈:分为本地方法栈和虚拟机栈,本质上都是存储方法的栈帧,每次调用方法的时候,会进行压栈,方法调用完会执行出栈操作,本地方法栈执行的是C++方法,虚拟机栈执行的是 Java方法。
堆:存放 new 出来的对象的实例。
Test t = new Test();
new Test() 这个对象的实例一定是存储在堆上的。
t 需要分类讨论,如果 t 是一个局部变量,t 就是在栈上的;如果 t 是 成员变量,t 就是在堆上的;如果 t 是 静态成员变量,t 就是在元数据区里的。
元数据区 和 堆,整个Java进程共用一份
程序计数器和栈,每个线程有一份
在面试时,如果遇到谈一下栈和堆的话, 要注意是数据结构里的栈和堆, 还是JVM的栈和堆
类加载
1)加载:根据类的全限定名(包名+类名)找到对应的 .class 文件,然后打开文件,将文件的内容读取到内存中里。
2)验证:解析和校验 .class 文件的内容是否合法,如果合法就把这里的内容转化成结构化的数据
3)准备:给类对象申请 全0 的内存空间
4)解析:针对字符串常量进行初始化,将 .class 文件中的字符串常量放入元数据区的常量池中
5)初始化:将类对象进行最终的初始化,包括对类对象各种属性的填充,类中的静态成员,父类,如果父类没有被加载过,会触发父类的类加载。
类加载触发的时机为懒加载,当Java代码需要用到哪个类才会触发哪个类的加载
双亲委派模型
双亲委派模型的根据JVM实现类加载的源码提出的,也就是说是先有JVM的类加载源码,才有后面的双亲委派模型。
JVM 默认提供了三种类加载器,分别为 BootstrapClassLoader、ExtensionClassLoader、ApplicationClassLoader
你可以认为这三个类加载器的关系如下:
它们之间的联系,你可以认为是这三个类加载器都有一个引用指向上一个类加载器,ApplationClassLoader 的父亲的 ExtensionClassLoader,ExtensionClassLoader 的父亲是 BootstrapClassLoader,BootstrapClassLoader 的父亲为 null。
BootstrapClassLoader 负责加载Java 标准库的 .class 文件
ExtensionClassLoader 负责加载 Java 扩展库的 .class 文件
ApplicationClassLoader 负责加载 Java第三方库的.class 文件
随着时代的发展,Java的扩展库我们很少使用,取而代之的是Java第三方库,例如使用maven 加载的库就是第三方库
双亲委派模型的执行流程:
进行类加载,通过全限定类名寻找 .class 文件,先从 ApplicationClassLoader 最为入口开始,然后将类加载任务委托上一级 ExtensionClassLoader ,再将类加载任务委托给上一级 BootstrapClassLoader,由于 BootstrapClsssLoader 没有上一级,开始执行类加载任务,将需要的Java标准库里的 .class 文件加载到内存里,然后将任务下放给下一级 ExtensionClassLoader ,ExtensionClassLoader 将所需要的Java扩展库的 .class 文件加载到内存里,最后将任务交给下一级 ApplicationClassLoader,ApplicationClassLoader 负责加载Java第三方库的 .class 文件。
如果没有找到对应的 .class 文件,就会抛出异常 ClassNotFoundException
垃圾回收 GC
在Java中你不需要手动释放内存,这是因为JVM 内部实现了 GC,也就是垃圾回收机制,这个机制可以自动回收内存空间,这使得Java程序员不需要考虑内存泄漏的问题。
垃圾回收有两个步骤:首先就是找到垃圾,然后再回收垃圾
如何找到垃圾???
找到垃圾这里介绍两个算法,一个是引用计数,另一个是可达性分析
引用计数
在创建的对象旁边开辟一个空间,用来存放该对象被多少个引用引用着,当被引用的数量为 0 的时候就会进行垃圾回收:
但这也有缺点:
1)内存消耗多,尤其是对象本身比较小的时候,引用计数占据的空间的比例就会很大,例如:假设对象自身占8个字节,引用计数可能占 4 个字节
2)可能出现 “ 循环引用” 的问题
假设一个类里面还定义了一个引用,用这个类创建的两个对象的引用相互指向对方,那这两个对象是不可能被垃圾回收掉的:
当我们将 a 和 b 两个引用置为 null 的时候,我们创建的两个对象的实例是不会被回收掉的,因为此时两个对象都被对方引用着,双方的引用计数均为 1,这就是 “循环引用”
可达性分析(JVM 使用)
为了解决上述引用计数产生的两个弊端(空间浪费和循环引用),这里提出了可达性分析算法。
可达性分析算法采用时间换空间的策略,这也是 JVM 寻找垃圾使用的算法
首先对代码的一些特定对象作为遍历的 “起点”:这些特定的对象包括 栈上的局部变量(引用变量)、常量池引用指向的对象、静态成员(引用类型的)【这些对象在程序运行到任何时刻都容易被捕获到的】
【因为不会扫描堆上的对象,所以不会存在因为 “循环引用” 而影响垃圾判断的现象】
然后进行遍历:判断某个对象是否能被访问到,在能访问到的对象标记为 “可达”。
当完成遍历后,把未标记为 “可达” 的对象标记为 “不可达”
JVM 通过上述操作,就知道哪些对象是 可达的,哪些是 不可达的,接下来就是回收垃圾的操作了。
举个例子:
class Node {Node left;Node right;
}public class Test2 {public Node build() {Node a = new Node();Node b = new Node();Node c = new Node();Node d = new Node();Node e = new Node();Node f = new Node();Node g = new Node();a.left = b;a.right = c;b.left = d;b.right = e;f.right = g;return a;}
}
由于方法最后只返回 a 这个节点,这时候 f 和 g 节点就会被回收掉。
如何处理找到的垃圾???
这里介绍四种处理方式:标记–清除 算法,复制算法,标记整理 算法,分代算法,其中最后一个算法 分代算法是 JVM 真正使用的。
标记–清除 算法
在需要回收的内存上做上标记,然后进行回收清除操作,这是最直接的算法,但是存在一个缺点就是会产生内存碎片。
举个例子:假设一共有 7 块内存块,经过可行性分析算法得出 2、4、6 这三块内存为需要回收的内存,先做上标记,然后进行回收释放,但是空出来的内存碎片可能难以得到利用。
标记整理算法
由于标记清除算法会产生大量的内存碎片标记整理算法直接将垃圾回收设计为类似顺序表删除的形式, 将非垃圾的对象排到一起, 这样就可以空出大块的空闲内存块了.
但是缺点也是显而易见的, 就是系统开销比较大, 尤其是移动较大的对象的时候.
复制算法
将内存空间一分为二,当需要进行垃圾回收的时候,将非垃圾的内存块依次紧凑地复制到另一半内存中。
但是也存在两个缺点
1)内存消耗大,内存的空间利用率低
2)一旦非垃圾的内存块较多的时候,复制的成本就会较高,尤其是复制包含较大的对象的时候。
举个例子:要回收 1 和 4 号内存块。
分代算法 (JVM 使用)
分代算法是结合了上面两种算法的优点,取长补短的综合算法
JVM 将对象划分为 新生代和老年代,新生代又划分了三个区域分别是伊甸区、两个幸存区【空间占比为8:1:1】
分代算法的代指的是对象的年龄大小, 年龄的大小和 GC 轮次相关
命名的来源于圣经,人类发源地伊甸园,在这里指新生成的对象的存放位置,由于灭世洪水的降临,人类打造了诺亚方舟,成功躲避天灾的人门就是幸存者,这里的幸存区是指对象经过GC之后还能存留下来的存储位置
我们认为对象一开始生成的时候,是最容易被 GC 掉的,所以新生成的对象保存在 伊甸区里,经过 一轮GC 之后剩下的对象不会很多,将这些幸存的对象放到幸存区里,两个幸存区就是为了执行复制算法,经过多轮 GC 之后,还能在幸存区里存活的对象将放入到老年代。
一般来说,如果内存占用空间比较大的对象我们一般是直接放入老年代, 减少系统开销
新生代的 GC 频次较高
老年代的 GC 频次较低
因为我们认为要 GC 掉的早就 GC 掉了,之所以能存活在老年代,说明这个对象经常被使用,也就是说老年代的对象不需要高频次的 GC 次数,GC 的周期可以长一点,减少系统开销。
相关文章:

浅谈 JVM
JVM 内存划分 JVM 内存划分为 四个区域,分别为 程序计数器、元数据区、栈、堆 程序计数器是记录当前指令执行到哪个地址 元数据区存储存储的是当前类加载好的数据,包括常量池和类对象的信息,.java 编译之后产生 .class 文件,运…...
html的iframe页面给帆软BI发送消息
需求:帆软的网页组件嵌套一个HTML页面,HTML页面要给帆软发消息。 解决方法是:fineReportWindow.duchamp.getWidgetByName("txt1").setValue(666); <!DOCTYPE html> <html lang"en"> <head> <…...

spark任务优化参数整理
以下参数中有sql字眼的一般只有spark-sql模块生效,如果你看过spark的源码,你会发现sql模块是在core模块上硬生生干了一层,所以反过来spark-sql可以复用core模块的配置,例外的时候会另行说明,此外由于总结这些参数是在不…...

C++ 模拟真人鼠标轨迹算法 - 防止游戏检测
一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言,原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势: 模拟…...

生产环境中常用的设计模式
生产环境中常用的设计模式 设计模式目的使用场景示例单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点- 日志记录器- 配置管理器工厂方法模式定义一个创建对象的接口,让子类决定实例化哪个类- 各种工厂类(如视频游戏工厂模式创…...

基于SpringBoot+Vue的药品管理系统【源码+文档+部署讲解】
系统介绍 基于SpringBootVue实现的药品管理系统采用前后端分离的架构方式,系统实现了用户登录、数据中心、药库管理、药房管理、物资管理、挂号管理、系统管理、基础设置等功能模块。 技术选型 开发工具:idea2020.3Webstorm2020.3 运行环境ÿ…...
【CompletableFuture实战】
CompletableFuture实战 前言 前言 过去的一年,匆匆忙忙,换了一次工作,写博客的习惯就落下了,总之,有点懈怠。希望今年能重拾信心,步入正规! CompletableFuture的用法网上资料颇多,…...
Redis 缓存穿透、击穿、雪崩 的区别与解决方案
前言 Redis 是一个高性能的键值数据库,广泛应用于缓存、会话存储、实时数据分析等场景。然而,在高并发的环境下,Redis 缓存可能会遇到 缓存击穿、缓存穿透 和 缓存雪崩 这三大问题。这些问题不仅影响系统的稳定性和性能,还经常出…...
Python自动化测试中定位隐藏菜单元素的策略
大家都读完觉得有帮助记得关注和点赞!!! 在进行Python自动化测试时,尤其是使用Selenium等工具对Web应用进行测试时,可能会遇到某些元素被隐藏的问题。这使得元素定位和交互变得复杂。然而,通过一些技术手段…...
【张雪峰高考志愿填报】合集
【张雪峰高考志愿填报】合集 链接:https://pan.quark.cn/s/89a2d88fa807 高考结束,分数即将揭晓,志愿填报的关键时刻近在眼前!同学们,这可是人生的重要转折点,选对志愿,就像为未来铺就一条…...

53,【3】BUUCTF WEB october 2019 Twice SQLinjection
题目得到信息,2次注入,进入靶场 登录页面,很自然想到SQL 第一次注入应该是这个可以登录,注册,提交简介的页面 第二次注入应该是在info处注入,信息显示在简介处 我真的纯脑子有病,人家二次注入不…...

【Linux系统】分区挂载
我们能够根据一个 inode 号在指定分区寻找目标文件的 struct inode,也能根据目录文件的内容,通过映射关系,找指定的 inode,可是,现在有个问题: 问题:inode 是不能跨分区使用的!Linu…...

Oracle 可观测最佳实践
简介 Oracle 数据库是一种广泛使用的商业关系数据库管理系统(RDBMS),由甲骨文公司(Oracle Corporation)开发。它支持 SQL 语言,能够存储和管理大量数据,并提供高级数据管理功能,如数…...

Ubuntu本地部署网站
目录 1.介绍 2.安装apache 3.网页升级 1.介绍 网站其实就相当于一个文件夹,用域名访问一个网页,就相当于访问了一台电脑的某一个文件夹,在网页中看见的视频,视频和音乐其实就是文件夹里面的文件。为什么网页看起来不像电脑文件夹…...

图数据库 | 18、高可用分布式设计(中)
上文我们聊了在设计高性能、高可用图数据库的时候,从单实例、单节点出发,一般有3种架构演进选项:主备高可用,今天我们具体讲讲分布式共识,以及大规模水平分布式。 主备高可用、分布式共识、大规模水平分布式ÿ…...

Java 读取 Windows 设备的唯一性标识及定位
在 Windows 系统中,获取设备唯一性标识及定位信息对设备管理、安全监控等场景意义重大。本文介绍 Java 中几种实现方法,如 JNA 库、WMI4Java 库及通过 JNI 结合 Windows API。 1. 使用 JNA 库读取 DEVPKEY_Device_ContainerId 在 Windows 系统中&…...
Spring boot框架下的RabbitMQ消息中间件
1. RabbitMQ 基础概念 1.1 消息处理流程与组件配合 Producer(生产者) 发送消息。消息先发送到 Exchange(交换机),而不是直接到队列。Exchange(交换机) 接收到消息后,根据 Routing …...

1 行命令引发的 Go 应用崩溃
一、前言 不久前,阿里云 ARMS 团队、编译器团队、MSE 团队携手合作,共同发布并开源了 Go 语言的编译时自动插桩技术。该技术以其零侵入的特性,为 Go 应用提供了与 Java 监控能力相媲美的解决方案。开发者只需将 go build 替换为新编译命令 o…...

ScratchLLMStepByStep:训练自己的Tokenizer
1. 引言 分词器是每个大语言模型必不可少的组件,但每个大语言模型的分词器几乎都不相同。如果要训练自己的分词器,可以使用huggingface的tokenizers框架,tokenizers包含以下主要组件: Tokenizer: 分词器的核心组件,定…...

G1原理—10.如何优化G1中的FGC
大纲 1.G1的FGC可以优化的点 2.一个bug导致的FGC(Kafka发送重试 subList导致List越来越大) 3.为什么G1的FGC比ParNew CMS要更严重 4.FGC的一些参数及优化思路 1.G1的FGC可以优化的点 (1)FGC的基本原理 (2)遇到FGC应该怎么处理 (3)应该如何操作来规避FGC (4)应该如何操…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...

《架构即未来》笔记
思维导图 第一部分:可扩展性组织的人员配置 第二部分:构建可扩展的过程 第三部分:可扩展的架构方案 第四部分:其他的问题和挑战 资料 问软件工程研究所: https://www.sei.cmu.edu/ AKF公司博客: http://www.akfpart…...