Java8永久代被移除
OutOfMemoryError
,这是由于您的HotSpotVM的PermGen空间耗尽造成的。这个问题很常见,通常是由于应用程序的动态重新部署(例如,从应用程序服务器加载和卸载Java EE应用程序)通常会触发类元数据泄漏;最终导致固定PermGen空间完全耗尽。
然而,oraclejrockit和ibmjre一开始并没有使用PermGen空间。它们使用C堆(本机内存)来存储类元数据。
当前的oraclejvm策略是将HotSpot和JRockit产品线合并到一个JVM项目中,该项目将包含每个VM的最佳特性。
没有永久代的未来对你意味着什么?
没有PermGen空间意味着不再通过–XX:PermSize
&-XX:MaxPermSize
配置和调整此内存空间,因为类元数据将移动到本机内存(C-Heap)和OldGen空间,不再可配置。
但是,我建议您提高对本机内存空间(例如C-Heap)的警觉性和监视级别。与Java堆一样,您可能仍然面临本机内存空间的容量或泄漏问题,因此请确保在JVM容量规划练习中包含此分析。
永久空间移除了吗?
还不完全。正如在Oracle博客中提到的,PermGen的删除需要一段时间,所以在java7的更多版本发布之前不要期望完全删除。
最后,我使用Java 7示例程序运行了一个简单的测试详细:gc已打开如您所见,PermGen内存空间仍然存在于这个热点版本(构建21.0-b17)中。
Java8中的metaspace元空间
在这篇文章中,我们将看到一个JVM更新,即删除永久代生成。在这里,我们将看到为什么需要删除永久代和它的替代元空间。
这就是Java6中堆结构的样子
永久代Permgen
包含虚拟机本身的所有反射数据的池,例如类和方法对象。对于使用类数据共享的javavm,这一代分为只读和读写两部分。
永久生成包含JVM描述应用程序中使用的类和方法所需的元数据。永久生成由JVM在运行时根据应用程序使用的类填充。此外,javase库类和方法可以存储在这里。
如果JVM发现不再需要类,并且其他类可能需要空间,则可以收集(卸载)这些类。永久生成包含在完整的垃圾收集中
- 用于JVM类元数据的Java堆区域。
- Hotspot对Java类的内部表示。
- 类层次结构信息、字段、名称
- 方法编译信息和字节码
- 变量
- 常数池与符号分解
PermGen永久代大小
限制为MaxPermSize–默认值为64M-85M
与Java堆相邻:使用非连续堆-card table(一种记录一代中oop发生变化的记忆集)来识别旧gen和permgen的年轻引用将更加昂贵和复杂。
一旦耗尽抛出内存错误“永久空间”。
- 应用程序可以清除导致类卸载的引用。
- 使用更大的MaxPermSize重新启动。
所需的大小取决于类的数量、方法的大小、常量池的大小。
为什么PermGen被淘汰了?
- 启动时大小固定-难以调整。
- -XX: MaxPermSize=?
- 内部热点类型是Java对象:可以用完整的GC移动,不透明,不强类型,很难调试,需要元数据。
- 简化完整集合:每个收集器的元数据的特殊迭代器
- 想同时释放类数据,而不是在GC暂停期间
- 实现PermGen限制的未来改进。
JVM元数据现在去了哪里?
metaspace元空间
永久生成(PermGen)空间已经被完全移除,并被一个称为元空间的新空间所取代。
删除PermGen的结果是,显然PermSize和MaxPermSize JVM参数被忽略,您永远不会得到java.lang.OutOfMemoryError:PermGen
错误。
jdk8热点JVM现在使用本机内存来表示类元数据,称为Metaspace。
- 利用Java语言规范属性:类和关联的元数据生存期与类装入器的生存期匹配。
- 每个装载机存储区域–元空间
- 仅线性分配
- 不单独回收(除了重定义类和类加载失败)
- 无GC扫描或压缩
- 无需重新定位元空间对象
- 类加载器被GC发现死机时集体回收
java8metaspace内存溢出的排查思路可参考这篇文章:https://javakk.com/160.html
元空间内存分配模型
- 类元数据的大多数分配现在都是从本机内存中分配的。
- 用于描述类元数据的类已被删除。
- 为元数据分配了多个映射的虚拟内存空间。
- 按类装入器块列表分配
- 块大小取决于类装入器的类型。
- sun/reflect/Delegating类加载器的较小块。
- 将区块返回到空闲区块列表。
- 清空时返回虚拟内存空间。
- 减少分裂的策略。
我们将看到如何为元数据分配虚拟内存空间,以及它如何使用此图片加载每类加载程序
您可以看到如何分配虚拟内存空间(vs1、vs2、vs3)以及如何分配每个类装入器块。CL-类加载器
理解“_mark标记”和“_klass指针”
要理解下一个图表,您需要了解这些指针。
在JVM中,每个对象都有一个指向其类的指针,但只指向其具体类,而不指向其接口或抽象类。
对于32位JVM:
_标记:4字节常量
_klass:指向类的4字节指针
内存中对象布局中的第二个字段(对于32位JVM,偏移量为4,对于64位JVM,偏移量为8,从内存中对象的地址开始偏移量为8)指向内存中对象的类定义。
对于64位JVM:
_标记:8字节常量
_klass:指向类的8字节指针
对于具有压缩OOP的64位JVM:
_标记:8字节常量
_klass:指向类的4字节指针
Java对象内存布局
带有压缩指针的Java对象内存布局
压缩指针摘要
- 64位平台的默认值。
- 压缩对象指针
-XX:+UseCompressedOops
- “oops”是“普通”对象指针。
- 对象指针在Java堆中的对象中被压缩到32位。
- 使用堆基(如果Java堆在较低的26G内存中,则为零)。
- 压缩类指针
-XX:+UseCompressedClassPointers
。 - 对象有一个指向VM元数据类(第二个字)的指针,该类压缩为32位。
- 使用压缩类指针空间的基。
元空间与压缩类指针空间的区别
- 压缩的类指针空间只包含类元数据。
- InstanceKlass,arraylass
- 仅当UseCompressedClassPointers为true时。
- 出于性能考虑,其中包括Java虚拟表。
- 我们仍在缩小此元数据类型。
- Metaspace包含所有其他可能很大的类元数据。
- 方法,字节码,ConstantPool。。。
元空间调整
可以使用-XX:MaxMetaspaceSize
标志设置最大元空间大小,默认值为无限,这意味着只有系统内存是限制。-XX:MetaspaceSize调优标志定义了元空间的初始大小,如果不指定此标志,则元空间将根据运行时的应用程序需求动态重新调整大小。
调整标志-MaxMetaspaceSize
- -XX: MaxMetaspaceSize={unmited}
- 元空间受计算机上内存量的限制。
- 在发生过度交换和本地分配失败之前,限制类元数据使用的内存。
- 如果怀疑类装入器内存泄漏,请使用。
- 如果地址空间可能耗尽,请在32位上使用。
- 初始MetaspaceSize 21 mb–GC初始高水位标记,用于完成完整的GC收集类。
- GC的目的是检测死区类装入器和卸载类。
- 如果启动时执行太多GC,则设置为更高的限制。
- 可能使用PermSize设置的相同值来延迟初始GC。
- 高水痕随着后续收集的增加而增加,在下一次元空间GC之前,合理数量的主室。
- 请参见
MinMetaspaceFreeRatio
和MaxMetaspaceFreeRatio
- 与类似GC自由比参数类似的解释
调整标志-CompressedClassSpaceSize
- 仅当
-XX:+UseCompressedClassPointers
(默认值为64位)时有效。 -XX:CompressedClassSpaceSize
=1G。- 由于这个空间目前在启动时是固定的,所以一开始就要保留大量空间。
- 使用前不提交。
- 未来的工作是使这片空间变得可扩展。
- 不需要是连续的,只能从基地址访问。
- 而是将更多的类元数据转移到元空间。
- 将来可能会根据PredictedLoadedClassCount(现在是实验标志)进行人体工程学设置。
- 设置其他内部JVM数据结构的大小,如加载类的字典。
元空间工具
- jmap-permstat选项重命名为jmap-clstats
- 打印Java堆的类装入器统计信息。对于每个类装入器,将打印其名称、活动性、地址、父类装入器以及它已加载的类的数量和大小。此外,还打印了内插字符串的数量和大小。
- jstat-gc选项显示Metaspace而不是PermGen。
- jcmd<pid>GC.class_stats统计.
- 提供类元数据大小的详细柱状图。
- 使用
-XX:+UnlockDiagnosticVMOptions
启动java
改进的GC性能
如果您很好地理解了元空间的概念,就很容易看到垃圾收集方面的改进
- 在完全收集期间,不扫描指向元数据指针的元数据。
- 删除了许多用于元数据扫描的复杂代码(尤其是CMS)。
- Metaspace包含一些指向Java堆的指针。
- 指向类元数据中java/lang/Class实例的指针
- 指向数组类元数据中组件java/lang/Class的指针
- 没有压缩元数据的成本。
- 减少根扫描(不扫描已加载类的VM字典和其他内部哈希表)。
- 缩短完整收集时间。
- 并行标记循环后G1中的类卸载工作
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/476.html
暂无评论