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)从这个字节码中可以看到,stack是操作数栈的深度是2,局部变量表一共有两个元素,参数是1

2)现在来看Code代码,首先执行new字节码的操作指令,看到这里是#2,然后去找Object,首先会进行判断运行时常量池里面是否已经加载了Object类,如果没有加载过,那么直接使用ClassLoader将java/lang/Object类直接加载到方法区,并在堆上开辟内存空间

中间有一个指针进行标识空闲空间和非空闲空间的一个划分区域,当存放完成新的对象以后,指针会向右移

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

iPhone手机屏幕分辨率

ios app测试时,需要测试应用在不同型号的苹果手机上的表现形式,可以自己在浏览器上配置。 代数设备逻辑像素尺寸缩放发布时间第一代iPhone 2G320 x 480480 x 3203.5寸1x2007年6月29日第二代iPhone 3320 x 480480 x 3203.5寸1x2008年7月11日第三代iPhone …

OpenText 安全取证软件——降低成本和风险的同时,简化电子取证流程

OpenText 安全取证软件,行业标准的数字调查解决方案,适用于各种规模和各种行业的组织 降低成本和复杂性 • 远程调查比轮流调查过程更有效 对结果持有信心 • 磁盘级可见性可以完成相关端点数据的搜索和收集 谨慎调查 • 完整的网络调查&#xf…

sql server 生成连续日期和数字

在sqlserver里,可以利用系统表master..spt_values里面存储的连续数字0到2047,结合dateadd()函数生成连续的日期 select convert (varchar(10),dateadd(d, number, getdate()),23) as workday from master..spt_values where type…

【从瀑布模式到水母模式】ChatGPT如何赋能软件研发全流程

文章目录 🎄前言🍔本书概要🌺内容简介🌺作者简介🌺专家推荐🛸读者对象🍔彩蛋 🎄前言 计算机技术的发展和互联网的普及,使信息处理和传输变得更加高效,极大地…

【2023CANN训练营第二季】——通过一份入门级算子开发代码了解Ascend C算子开发流程

本次博客讲解的代码是Gitee代码仓的Ascend C加法算子开发代码,代码地址为: quick-start 打开Add文件,可以看到文件结构如下: 其中add_custom.cpp是算子开发的核心文件,包括了核函数的实现,展示了如何在Asc…

2023年【安全生产监管人员】考试报名及安全生产监管人员复审考试

题库来源:安全生产模拟考试一点通公众号小程序 安全生产监管人员考试报名是安全生产模拟考试一点通总题库中生成的一套安全生产监管人员复审考试,安全生产模拟考试一点通上安全生产监管人员作业手机同步练习。2023年【安全生产监管人员】考试报名及安全…

【数据结构练习】树和二叉树的选择题精选集锦

前言 编程想要学的好,刷题少不了,我们不仅要多刷题,还要刷好题!为此我开启了一个弯道超车必做好题锦集的系列,此为树和二叉树的选择题精选集锦。该系列会不定期更新,敬请期待! 1.已知某二叉树的…

SQLi靶场

SQLi靶场 less1- less2 (详细讲解) less 1 Error Based-String (字符类型注入) 思路分析 判断是否存在SQL注入 已知参数名为id,输入数值和‘ 单引号‘’ 双引号来判断,它是数值类型还是字符类型 首先输入 1 , 发现…

大语言模型在天猫AI导购助理项目的实践!

本文主要介绍了Prompt设计、大语言模型SFT和LLM在手机天猫AI导购助理项目应用。 ChatGPT基本原理 “会说话的AI”,“智能体” 简单概括成以下几个步骤: 预处理文本:ChatGPT的输入文本需要进行预处理。 输入编码:ChatGPT将经过预…

Postman接口测试,全网最详细教程

Postman的脚本可以导出多种语言的脚本,方便二次维护开发。 Python的requests库,支持python2和python3,用于发送http/https请求 使用unittest进行接口自动化测试 0 1****环境准备 1、安装python (使用python2或3都可以&#x…

【表面缺陷检测】铝型材表面缺陷检测数据集介绍(含xml标签文件)

一、铝型材介绍 铝型材是一种由铝合金材料制成的,具有固定截面形状和尺寸的条形建材。由于其优良的物理性能和广泛的应用领域,铝型材在现代工业和生活中发挥着重要的作用。 1、铝型材的分类 根据截面形状的不同,铝型材可分为角铝、槽铝、工…

鉴源实验室 | AUTOSAR E2E:车载通信的安全保障

作者 | 沈平 上海控安可信软件创新研究院汽车网络安全组 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 随着汽车行业逐步走向电气化、智能化,车载系统的软件和硬件复杂度不断上升。如何确保这些复杂系统中的数据通讯安全和…

在线设计数据库表用Itbuilder,极简易用真香!!!

“如果您想要一个具有快速搜索运行的高性能数据库,那么数据库设计是必不可少的,花时间设计数据库将帮助您避免效率低下和高冗余等问题”。 在线数据库设计软件itbuilder,界面清爽漂亮,功能简洁,没有多余设置很容易上手…

DevOps持续集成-Jenkins(4)

文章目录 DevOpsDevOps概述Jenkins流水线任务入门⭐Jenkins流水线任务的Hello World体验⭐Jenkins流水线语法例子Jenkins流水线语法生成器⭐ Jenkins实战4:构建pipeline(流水线)的Jenkins项目⭐项目架构图Jenkins实战4的初步流水线模板&#…

直播预告 | YashanDB 2023年度发布会正式定档11月2日,邀您共同见证国产数据库发展实践!

11月2日,YashanDB 2023年度发布会将于云端直播开启,发布会以 「惟实励新」 为主题,邀请企业用户、合作伙伴、广大开发者共同见证全新产品与解决方案。届时发布会将在墨天轮社区同步进行,欢迎大家报名! 惟实求真。Yasha…

redis中的io多线程(线程池)

文章目录 redis多线程模型redis为什么引入I/O多线程I/O多线程模型 源码解析测试设置连接建立数据传输线程调度开启io线程startThreadedIO关闭io线程stopThreadedIO redis多线程模型 redis为什么引入I/O多线程 Redis 的性能瓶颈在网络 IO 的处理上。Redis 是网络 IO 密集型&am…

《ATTCK视角下的红蓝对抗实战指南》一本书构建完整攻防知识体系

一. 网络安全现状趋势分析 根据中国互联网络信息中心(CNNIC)发布的第51次《中国互联网络发展状况统计报告》,截至2022年12月,我国网民规模为10.67亿,互联网普及率达75.6%。我国有潜力建设全球规模最大、应用渗透最强的…

雪糕冰淇淋经营配送小程序商城效果如何

雪糕冰淇淋是很多年轻人喜欢的食品之一,市面上的雪糕品牌类型众多,销售模式主要为厂家批发、经销商零售等,由于雪糕冰淇淋的易化性,很多用户会选择就近购买,但制作技术升级和长途冷藏技术下,网购成为另一种…

建模仿真软件 Comsol Multiphysics mac中文版软件介绍

COMSOL Multiphysics mac是一款全球通用的基于高级数值方法和模拟物理场问题的通用软件,拥有、网格划分、研究和优化、求解器、可视化和后处理、仿真 App等相关功能,轻松实现各个环节的流畅进行,它能够解释耦合或多物理现象。 附加产品扩展了…

基于Java的电动车实名挂牌系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding) 代码参考数据库参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…
最新文章