JVM进阶(2)
一)方法区:
java虚拟机中有一个方法区,该区域被所有的java线程都是共享,虚拟机一启动,运行时数据区就被开辟好了,官网上说了方法区可以不压缩还可以不进行GC,JAVA虚拟机就相当于是接口,具体的HotSpot就是虚拟机的实现,因为永久代还是使用的是JAVA虚拟机的内存,
方法区域可以是固定大小的,也可以根据计算的需要扩展,如果不需要更大的方法区域,则可以收缩,物理上是不连续的,在逻辑上是连续的;
1)方法区和JAVA堆一样,是各个线程共享的内存区域
2)方法区在JVM启动的时候就被创建,并且它的实际的物理内存空间和JAVA队去一样都可以是不连续的
3)方法区的大小和堆空间一样,可以选择固定大小或者是可扩展
4)方法去的大小决定了系统可以保存多少各类,如果系统定义了太多的类,导致方法去溢出,虚拟机同样也会抛出内存溢出错误,java.lang.OutOfMemory:perm space(永久代空间溢出)或者是java.lang.OutOfMemeory:MeatSpace(元空间空间溢出),比如说大量加载第三方jar包,Tomact部署的工程过多,大量的动态生成反射类,加载大量第三方jar包,Tomact部署的应用程序太多,一个简单的代码可能要加载很多类,动态生成反射类,比如说动态代理,元空间不在虚拟机设置的内存中,而是使用本地内存物理内存,字符串常量池和静态变量也会变化,但是如果超过本地内存上限,也会发生OOM metaSpace,因为方法区是不共享的,所以说只能有一个类可以调用类加载器实现类加载;
5)关闭JVM就会释放这个区域的内存,JDK7以前,习惯上把方法区称之为是永久代,JDK8开始使用元空间替代了永久代,本质上方法区和永久代并不是等价的,但是仅仅是针对于HotSpot虚拟机而言的;也就是JAVA虚拟机规范,对于如何实现方法区不会做统一要求,现在来看使用永久代共容易出现OOM;
6)元空间的本质和永久代类似,都是对JVM规范中方法去的实现,不过元空间和永久代最大的区别在于元空间不在虚拟机设置的内存中,二时使用的是本地内存,永久代和元空间不光名字变了,况且内部结构也调整了,根据JAVA虚拟机规范规定,如果方法去无法满足新的内存分配的需求的时候,会抛出OOM异常,本地内存是无限大的,况且静态变量字符串常量池等等也会变化;
-XX:MetaspaceSize=100m,-XX:MaxMetaspaceSize=100m
一般在实际开发中会进行设置MetaspaceSize,不会设置MaxMetaspaceSize是默认值-1即可,这个Metaspace一开始要设置的大一些,为了避免频繁的发生FullGC导致调整水平线
方法区用于存放已经被虚拟机加载的类型信息,常量,静态变量以及即时编译器编译过后的代码缓存
1)类型信息:对于每一个加载的类型(类 class,接口 interface,枚举Enum,注解 annoation),JVM必须在方法中存放一下类型信息:
1)这个类型的完整有效名称(全名=包名+类名)
2)这个类型直接的父类的完整有效名字(对于interface和java.lang.object,都是没有父类的)
3)这个类型的修饰符
4)这个类直接接口的有效列表
2)域信息:就是成员变量的属性,JVM必须在方法区中保存类型的所有域的相关信息以及域的声明顺序,域的相关信息包括,修饰符,关键字等等,名称类型,修饰符,在方法区中也是保留着这个类信息是被哪一个类加载器加载进来的,类加载器的信息也是在类的信息中是有纪录的,同时类加载也会记录他都加载过那些类,彼此相互记录;
3)方法信息:操作数栈的深度,方法的权限,形参,局部变量表的深度,以及try catch包裹的代码范围信息;
上面的这段代码执行也不会出现空指针异常,被static和final修饰的量是在编译过程中的准备阶段就被附上初值了
Class文件常量池:每个.Java源文件编译后生成.Class文件中会保存当前类中的字面常量以及符号信息
运行时常量池:在.Class文件被加载时,.Class文件中的常量池被加载到内存中称为运行时常量池,运行时常量池每个类都有一份
字符串常量池(StringTable) :字符串常量池在JVM中是StringTable类,实际是一个固定大小的HashTable(一种高效用来进行查找的数据结构),不同JDK版本下字符串常量池的位置以及默认大小是不同的;
二)运行时常量池:
方法区中包含了字符串常量池,字节码文件内部包含了常量池,要想弄清楚方法区,需要清楚的理解ClassFile,因为本身加载类的信息都在方法区,所以要想弄清楚方法区的运行时常量池,就需要先学会ClassFile中的常量池
常量池:字面量(10,20),字符串本身,System,out等等类型信息这些都会对应着一个符号
类型信息,方法引用,接口信息,只是存储一份,节省空间,通过符号引用就可以直接找到对应的常量池对应字段的位置
class文件常量池:this也是以字面量的方式及进行存储的
1)方法区的运行时常量池:就是字节码文件中每一个类的接口对应的常量池表在运行时后的一个表示形式,类型信息,方法,字段,常量字段,属性引用,方法引用\
2)常量池就相当于是一张表,JVM指令需要根据这张表来找到要执行的类名,方法名,参数类型,字面量等类型,连方法名都被符号引用所代替了class文件常量池被加载到方法去以后就变成了运行时常量池;
3)运行时常量池是方法区的一部分,常量池表是Class文件的一部分,用于存放编译器的生成的各种字面量和符号引用,这部分内容将被类加载以后存放到方法区的运行时常量池中
4)运行时常量池在加载类和接口到虚拟机以后,就会创建对应的运行时常量池
JVM为每一个已经加载的类型,类或者是接口都维护一个常量池,池子中的数据项像数组项一样,都是通过索引来进行访问的,比如说#7;
5)运行时常量池中包含着多种不同的常量,包括编译时期就已经确定的数值字面量,也包括到运行时期解析才可以获得的方法或者是字段引用,此时就不是常量池中的符号引用了,而是转化成了真实地址,运行时常量池,相比于class文件常量池的另一个重要特征就是具备动态性,String.intern(),运行时常量池类似于传统编程语言中的符号表,但是它所包含的数据要比符号表要更丰富一些;
6)当创建类或者是接口的运行时常量池的时候,如果构建运行时常量池的所需要的内存空间方法去所能提供的最大值,JVM会抛出OOM异常;
三)方法区的迭代:
1)首先先明确一下,只有HotsSpot才存在永久代,BEA JRockit,IBM J9等来说,是不存在永久代的概念的,原则上如何实现方法区属于虚拟机实现的内部细节,不受JAVA虚拟机规范约束,并不要求统一
2)JDK6以前,只有永久代,静态变量就存放在永久代上面
3)JDK7存在永久代,但是已经逐步去除永久代,字符串常量池,静态变量仍然在堆里面
4)JDK8没有永久代,类型信息,字段方法,常量仍然保存在本地内存的元空间,但是字符串常量池,静态变量仍然在堆空间里面;
1)之所以要取消永久代是因为JAVA官方收购了JRocket,之后将JRocket和HotSpot进行整合的时候,因为JROCKet没有永久代,所以就把永久代给移除了;
2)为什么JRocket没有永久代呢?
随着JAVA8的到来,HotSpot VM中再也见不到永久代了,但是这并不意味着类的元数据信息也消失了,这些数据被动到了一个和堆没有任何关系的本地内存区域,这个区域叫做元空间,由于类的元数据信息分配在本地内存中,元空间最大可分配空间就是系统可用内存空间,这项改动是非常有必要的,因为:
2.1)为永久代设置空间大小很难确定:在某些场景下,如果说动态的加载类过多,很容易产生Perm区的OOM,比如说在某一个Web工程中,因为功能点比较多,那么在运行过程中,要不断地加载很多类,但是具体加载的类的多少和大小程序员是很难进行确定的,经常出现致命错误,空间小容易出现FullGC,STW时间比较长,如果发生FullGC以后没有回收什么类,就容易出现OOM,分配大了浪费空间,但是元空间max=-1,更不容易发生fullGC
2.2)对永久代的调优很困难,永久代发生FGC,JVM判断常量池废弃的常量和不再使用的类也很浪费时间,影响程序执行的性能,所以说要尽量少出现FullGC
在JAVA7中方法区的实现是依靠永久代来实现的,主要存储的是运行时常量池,class类信息等等,永久代是JVM运行时运行数据区的一块内存空间,可以通过-XX PermSize来设置永久代的大小,当内存不够的时候就会触发垃圾回收,但是JDK1.8使用元空间来替代方法区的数据存储,元空间不属于JVM内存,而是本地内存,正常情况下元空间是可以无限制的使用本地内存的,但是还是可以通过参数来设置JVM元空间的使用内存大小
1)在JDK1.7的永久代是有内存限制的,是虚拟内存,虽然可以通过参数来进行设置,但是JVM加载的class总数是很难确定的,所以很容易出现OOM的问题,但是元空间是存储在本地内存里面,内存的上限是比较大的,很好的避免这个问题;
2)永久代的对象是通过fullGC进行垃圾回收的也就是和老年代同时实现垃圾回收,替换以后简化了fullGC的过程,可以不再进行暂停的情况下去并发释放类的数据,同时也提升了GC的性能
3)Orcle公司要合并Hotspot和Jrockit的代码,但是Jrockit没有永久代
方法区使用的是虚拟机内存,和本地内存有一个映射关系,JDK8使用本地内存,此时元空间大小只是受本地内存的影响,是不是虚拟内存是程序员本身设置的,通过一定的方式将虚拟内存映射到直接内存中,类多,方法多,不确定到底开辟多大的永久代,空间小,引起fullGC,STW时间长,但是又不能回收,最后只能造成OOM,如果开辟空间越大,也会造成浪费永久代出现full GC,对永久代调优是很困难的,永久代万一进行垃圾回收,判断类和常量不再使用,所以说尽量少出现full gc
元空间默认的初始值是21M,各种加载的类信息都要存放到方法区里面,如果Web应用系统加载的类信息直接大量存放在方法区达到了21M,那么此时会触发Full GC,不光会回收堆还会回收方法区,会对方法区中某一些无用的信息进行回收;
方法区容量分配大小的自动扩容机制:
1)假设一次FullGC之后方法区的垃圾回收回收了很多对象,剩余的方法区的空间大小是1M,那么此时的方法区下一次触发FullGC的内存大小就是回比21M小,也就是15M;
2)假设这一次FullGC方法区的垃圾回收基本没回收对象,那么下一次触发FullGC的达到的空间就会变得更高,会根据方法区这一次回收的大小自动做扩容
3)推荐设置此值,很容易放满,就有可能频繁触发FullGC,必须设置此值,不要说让方法区进行自动扩容,就不会让他每一次进行FullGC,进行动态扩容,防止大量进行FullGC;
静态变量staticObj和Class对象存放在一起,而Class对象又是存放在堆空间中的
方法区和永久代有什么区别?
方法区是JAVA虚拟机规范时候给的一个概念,包括JAVA虚拟机的运行时数据区
但是Hotspot针对于方法区的实现给出了不同的名称
JDK1.7永久代=方法区实现,但是JDK1.8元空间=方法区实现
方法区是定义的名称,但是永久代和元空间都是方法区的实现而已
五)JDK1.8方法区有什么优化?
1)将元空间改成了直接内存
2)将字符串常量池移动到了堆上
在JAVA开发中最常用的两个类型就是对象和String类型,字符串常量池比较大,最大的地方就要放在运行数据区的堆空间上
为什么把字符串常量池移动到堆上呢?
JDK7中将StringTable存放到了堆空间中,因为永久代的回收效率很低,在FullGC的时候才会被触发,但是FullGC是老年代的空间不足,永久代不足的时候才会触发,这就导致StringTable回收效率不高,而当开发中会有大量的字符串需要被创建,回收效率低,导致永久代内存不足,放到堆里面,可以及时的回收内存;
四)方法区的垃圾回收:常量池中废弃的常量以及不再使用的类变量
在大量使用到反射,动态代理,CGLIB等字节码框架,动态生成JSP以及频繁的自定义类加载器的场景,通常都是需要JAVA虚拟机具有类型卸载的能力,来保证不会对方法区有着很大的压力
4.1)类卸载的条件:ZGC不支持类卸载,一般来说这个区域的回收效果非常复杂难以让人满意,但是这部分区域的回收又是比较必要的
4.2)先来说说方法区中常量池之众所存放的两大类常量:字面量+符号引用
字面量是比较接近于JAVA语言层次的常量概念,比如说文本字符串,被声明成final的常量值等,但是符号引用就属于编译原理等方面的概念,包括以下三类常量:
1)类和接口的全限定名
2)字段的名称和描述符
3)方法的名称和描述符,HotSpot虚拟机对于常量池的回收策略是很明确的,只要常量池中的常量没有被任何地方所引用,就可以被回收
方法区中的类记录了它是由哪一个加载器进行加载的,类的加载器同时也会记录他加载过谁,类的加载器都被卸载了,那么A也会被干掉,但是通常类的加载器是一般不会被回收的
1)严重性:内存溢出>内存泄漏: 比如说ThreadLocal没有调用remove
2)内存泄漏最终会导致内存溢出,而内存溢出可能是内存泄漏导致的,比如说网络IO未释放资源
五)对象的实例化内存布局和访问定位
1)使用单例模式比如说静态方法
2)使用反射,Class的newInstance(),只能调用空参数的构造器,权限必须是public
3)Constructor的newInstance(XX),反射的方式可以调用空参,带有参数的构造器,权限没有要求
4)使用克隆,不需要调用任何构造器,但是必须当前类实现Cloneable接口,实现克隆方法
5)使用反序列化:从文件中和网络中来获取到一个对象的二进制流
1)从这个字节码中可以看到,stack是操作数栈的深度是2,局部变量表一共有两个元素,参数是1
2)现在来看Code代码,首先执行new字节码的操作指令,看到这里是#2,然后去找Object,首先会进行判断运行时常量池里面是否已经加载了Object类,如果没有加载过,那么直接使用ClassLoader将java/lang/Object类直接加载到方法区,并在堆上开辟内存空间;
中间有一个指针进行标识空闲空间和非空闲空间的一个划分区域,当存放完成新的对象以后,指针会向右移
设置对象的对象头
相关文章:

JVM进阶(2)
一)方法区: java虚拟机中有一个方法区,该区域被所有的java线程都是共享,虚拟机一启动,运行时数据区就被开辟好了,官网上说了方法区可以不压缩还可以不进行GC,JAVA虚拟机就相当于是接口,具体的HotSpot就是虚…...
2023大湾区杯粤港澳金融数学建模竞赛思路+模型+代码
目录 一.思路模型见文末名片,比赛开始第一时间更新 二.大湾区杯常用算法之主成分分析法(PCA) 三.MATLAB代码 四.国赛建模思路获取见此 一.思路模型见文末名片,比赛开始第一时间更新 二.大湾区杯常用算法之主成分分析法(PCA) 主成分分析法(PCA)是一种…...

【Note详细图解】中缀表达式如何转为后缀表达式?数据结构
中缀表达式 中缀表达式(中缀记法)是一个通用的算术或逻辑公式表示方法,操作符是以中缀形式处于操作数的中间(例:3 4),中缀表达式是人们常用的算术表示方法。 前缀或后缀记法不同的是…...
常用到的资源共享网站
1 资源共享 比你优秀的人都比你努力,你有什么理由不去努力。基础来自己的累秒累天累月的积累 没有一个人是从天而降的天才,也没有哪个人想做一个一生贫庸的人。今天我想说受人以鱼 不如受人以渔。 2 Java 开发软件的官网总结如下: Oracle Java 官网(https://www.oracle.com…...

关于JAVA中字节码文件版本号、产品版本号及开发版本号的关系
目录 关于字节码版本对应关系清单关于字节码格式说明的资料关于这些版本号 关于字节码版本 以二进制打开字节码文件: 如上图中第5-8标识(圈起来的)的即字节码版本号 十六进制: 34 十进制: 52 jdk 8 对应关系清单 …...

ModbusTCP 转 Profinet 主站网关在博图配置案例
兴达易控ModbusTCP转Profinet网关,在 Profinet 侧做为 Profinet 主站控制器,接 Profinet 设备,如伺服驱动器;兴达易控ModbusTCP 和 Profinet网关在 ModbusTCP 侧做为 ModbusTCP 从站,接 PLC、上位机、wincc 屏等。 拓…...

抖音上怎么挂小程序?制作小程序挂载抖音视频
公司企业商家现在已经把抖音作为营销的渠道之一,目前抖音支持短视频挂载小程序,可方便做营销。以下给大家分享这一操作流程。 一、申请自主挂载能力 首先需要在抖音开放平台官网注册一个抖音小程序账号,然后申请短视频自主挂载能力。 二、搭…...

AI新能量!FortiGate NGFW面向数据中心全面集成FortiGuard AI 安全服务
企业IT技术正在以惊人的速度发展,转型最大的领域之一是下一代防火墙(NGFW)市场。如今,混合云、多云、边缘等多种基础设施形态共存,已经成为大部分企业的常态,不断扩张的攻击面需要不同形态防火墙的安全防护…...

Git总结
Git介绍 一、Git常用命令 添加、提交 git add 将文件从工作区添加到暂存区,表示git开始追踪文件,如果不想让git追踪了,可以使用 git rm --cached <file> 取消文件追踪,仅仅只代表追踪取消,工作区文件还是照…...
初级前端面试题(一) 之 html/css/js
目 录 一、 HTML 1. .如何理解HTML语义化的? 2. HTML标签有哪些? 3. Canvas 和SVG的区别 二、CSS 1. BFC是什么? 2. 如何实现垂直居中? 3. css选择器 优先级如何确定? 4. 如何清除浮动? 5. …...

python实现excel的数据提取
一文带你实现excel表格的数据提取 今天记录一下如何使用python提取Excel中符合特定条件的数据 在数据处理和分析的过程中,我们经常需要从Excel表格中提取特定条件下的数据。Python的pandas库为我们提供了方便的方法来进行数据查询和过滤。 Pandas 是 Python 语言…...

Vue的MVVM实现原理
目录 前言 用法 代码和效果图 效果图 理解 高质量的使用 前言 MVVM是Model-View-ViewModel的缩写,是一种软件架构设计模式。Vue.js实现了这种设计模式,通过双向数据绑定和虚拟DOM技术,使得数据和视图能够快速响应彼此的变化。了解Vue的…...

vue+iView 动态侧边栏菜单保持高亮选中
iview 组件在使用过程中,多多少少有一些小坑,本文简单罗列一二: 避坑指南: 关于iview 侧边栏菜单未能展开高亮选中回显问题 应用场景:iview-admin下接入动态菜单后,刷新或链接跳入时回显失效 简单就是两个方…...

标准的听觉检测环境应满足哪些条件?
作者:兰明 医 学硕士,听力学 博士,听觉健康 门诊 主任。 听觉功能检测是一个计量的过程。国际和国家规定计量需要有一个标准的环境。目前有以下几种与听觉功能检测环境相关的国家标准或 /和国际标准: 1.《声学测听方法第1部…...

Fabric.js 样式不更新怎么办?
本文简介 带尬猴,我嗨德育处主任 不知道你有没有遇到过在使用 Fabric.js 时无意中一些骚操作修改了元素的样式,但刷新画布却没更新元素样式? 如果你也遇到同样的问题的话,可以尝试使用本文的方法。 是否需要重新绘制 我先举个例…...

【优选算法精品】前缀和
文章目录 一、前缀和前缀和问题一维前缀和模板二维前缀和模板 细节处理题目1思路细节处理: 题目2思路 题目3题目4题目5题目6总结 一、前缀和 前缀和问题 前缀和用来快速解决某一段连续区间的和。 时间复杂度O(1) 注意:不要背模板,不要背模…...

应用案例|基于高精度三维机器视觉引导机器人自动分拣包裹的应用
Part.1 行业背景 近年来,电商高速发展,百万件日订单处理的超大型分拣中心模式日益普及,传统的人工供包模式效率低,难以满足高超大分拣中心对分拣包裹的需求。随着科技的进步,自动供包系统进入大众视野,成为…...
Vue自定义指令实现按钮级的权限控制
通过v-指令,控制页面上的权限按钮的显示隐藏。首先是我的权限按钮数据,通过登录接口后端返回,前端将数据存在vuex里,在调用指令时候获取到当前页面对应的按钮权限数组,通过v-指令传递标识判断是否在当前页按钮权限数组…...
Selenium实现自动登录163邮箱和Locating Elements介绍
一. Selenium自动登录 代码如下所示: from selenium import webdriver from selenium.webdriver.common.keys import Keys import time #模拟登陆163邮箱 driver = webdriver.Firefox() driver.get("http://mail.163.com/") #用户名 密码 elem_user = …...

uniapp vue2、vue3 页面模板代码块设置
本文分享 uniapp vue2、vue3 页面模板代码块设置 设置路径 HBuilder X -> 工具 -> 代码块设置 -> vue代码块 -> 自定义代码块 如上图操作后在打开的 vue.json 文件的右侧“自定义代码块”中复制如下代码(可全选替换也可添加到代码中) 示…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...