栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

JVM方法区

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JVM方法区

方法区 堆,栈,方法区的交互关系

Person类的.classs信息放在方法区
penson变量存放在栈局部变量表
真正的对象放在Java堆
在person对象中有个指针指向方法区中的person类型数据,表明这个person对象是用方法区中的Person类new出来的

方法区基本理解

方法区看做是一块独立于堆的内存空间

方法区主要存放Class,类只能加载一次
物理上内存空间可以是不连续的
方法区大小决定可以保存多少个类
OOM实例:加载大量jar包 tomcat部署的工程多
关闭JVM就会释放这个区域的内存

演进

JDK7及以前 习惯上称为永久代 JDK8被元空间取代(方法区类比为接口,永久代或元空间类比为实现类)

永久代在虚拟机设置的内存中而元空间使用本地内存

元空间

元数据区 使用参数-XX:(Max)MetaspacesSize
默认值 windows 约21M, MAX 值是 -1 没有上限

初始高水平线21M 一旦触及,FullGC会被触发并卸载没用的类(即类对应的类加载器不在存活),然后这个高水位线将会重置,新的高水位线取决于GC后释放了多少元空间,如果释放的空间不足,不超过Max 适当提高水位线,如果释放空间过多则降低

如果初始设置过低 ,上述调整情况发生多次,通过GC日志可以观察到FullGC多次调用,为避免频繁GC 建议将设置一个相对较高的值

如何解决堆OOM

先简单了解
一般手段是确认内存中的对象是否是必要的,是内存泄露还是内存溢出

内存泄漏 ,对象不会在使用但还是有引用指向,导致不会被回收
如果是内存泄露 可进一步查看GC Roots引用链,根据泄露对象找路径,定位泄露代码的位置

如果对象都确实还必须,应当检查参数与物理内存对比看是否还能调大,从代码上检查是否存在某些对象生命周期过长的情况,尝试减少程序运行期的内存消耗

方法区存储什么?

《深入理解Java虚拟机》 书中对方法区描述:已被加载的类型信息,常量,静态变量,即时编译器后的代码缓存等

non-final 类型的类变量

全局常量 static final 在编译时就会被分配(写死在字节码文件)

运行时常量池VS常量池

运行时常量池在方法区内部

字节码内部包含常量池

常量池

一个有效的字节码文件除了包含类的版本信息,字段,方法以及接口等描述符信息外,还包含常量池表,包括各种字面量和对类型,属性,方法的符号引用

为什么需要

尽量只保存一份数据实体,用数据的时候去通过引用去使用数据,这是一种节约空间的思想,常量池可以看做是一张表,虚拟机根据这张表去找到要执行的类名,方法名,参数类型,字面量等类型,是符号地址

有啥

数量值
字符串值
类引用
字段引用
方法引用

运行时常量池

1,常量池加载到方法区后的名称
2,池中的数据项像数组一样通过索引访问
3,包含多种不同的常量,包括编译器就已经明确的数值字面两字面来那个,也包括4,到运行期解析后才能获得的方法或者字段引用,此时不再是常量池的符号地址了,这里换为真实地址。
5,具备动态性
6,当创建类或接口的运行时常量池时,可能会OOM

通过调用方法的函数去调用方法(需要类已加载,未加载则执行加载,将常量池符号引用(字面量)转换为直接引用)根据描述创建新栈帧

方法区演进细节
JDK6 静态变量 StringTable 和在方法区
JDK7 ~ 在堆
JDK8 方法区移到本地内存

永久代为什么被元空间取代

永久代在虚拟机内部,为永久代设置空间大小是很难确定的如果动态加载类过多会产生Perm的OOM,而元空间使用本地内存,大小仅受本地内存限制

对永久代调优很困难,垃圾回收:废弃的常量和不在使用的类,常量(主要字面量和符号引用)的回收类似对象的回收

方法区的调优主要是为了降低FUllGC

1 类型卸载条件苛刻
该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例。

加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则通常是很难达成的。

该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

2、Java虚拟机被允许对满足上述三个条件的无用类进行回收,这里说的仅仅是“被允许”,而并不是和对象一样,没有引用了就必然会回收。关于是否要对类型进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class 以及 -XX:+TraceClass-Loading、-XX:+TraceClassUnLoading查看类加载和卸载信息

3、在大量使用反射、动态代理、CGLib等字节码框架,动态生成JSP以及OSGi这类频繁自定义类加载器的场景中,通常都需要Java虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的内存压力。

StringTable为什么放到了堆?

因为永久代回收效率很低,在FullGC的时候才会执行永久代的垃圾回收,而FullGC是老年代,永久代不足时才会触发,在开发中会有大量的字符串被创建,导致永久代内存不足,放到堆里能及时回收

静态变量

JDK7及其以后把静态变量与类型在Java语言一端的映射Class对象存放在一起,存储在Java堆中

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/837371.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号