java permgen
Java虚拟机(JVM)使用其类的内部表示,该类包含每个类的元数据,例如类层次结构信息,方法数据和信息(例如字节码,堆栈和变量大小),运行时常量池以及已解析的符号引用和Vtables 。
过去(当定制类装入器并不常见时),这些类大多是“静态”的,很少被卸载或收集,因此被标记为“永久”。 另外,由于这些类是JVM实现的一部分,而不是由应用程序创建的,因此它们被视为“非堆”内存。
对于JDK8之前的HotSpot JVM,这些“永久”表示将存在于称为“永久生成”的区域中。 这个永久的生成与Java堆是连续的,并且被限制为-XX:MaxPermSize,该值必须在启动JVM之前在命令行上设置,或者默认为64M(对于64位可缩放指针为85M)。 永久代的收藏将与旧代的收藏联系在一起,因此,无论何时满员,永久代和旧代都会被收藏。 您可以立即调出的明显问题之一是对‑XX:MaxPermSize的依赖性。 如果类的元数据大小超出了‑XX:MaxPermSize的范围,则您的应用程序将耗尽内存,并且将遇到OOM(内存不足)错误。
Trivia:在JDK7之前,对于HotSpot JVM,在永久代(也称为PermGen)中还保留有interned-strings,从而导致大量性能问题和OOM错误。 有关从PermGen中删除插入字符串的更多信息,请参见此处 。
再见,再见PermGen,您好,Metaspace!
随着JDK8的到来,我们不再拥有PermGen。 不,元数据信息并没有消失,只是保存它的空间不再与Java堆相邻。 元数据现在已移至本机内存中的“ Metaspace”区域。
由于PermGen确实很难调整,因此必须迁移到Metaspace。 元数据可能会随每个完整的垃圾回收一起移动。 而且,由于对PermGen的大小取决于很多因素,例如类的总数,常量池的大小,方法的大小等,因此很难确定PermGen的大小。
此外,HotSpot中的每个垃圾收集器都需要专门的代码来处理PermGen中的元数据。 从PermGen分离元数据不仅允许对Metaspace进行无缝管理,而且还可以进行改进,例如简化完整的垃圾回收以及将来对类元数据的并发取消分配。
![](https://i-blog.csdnimg.cn/blog_migrate/f0ceb8a9fb4b3b70527e6074addbb523.png)
移除永久空间对最终用户意味着什么?
由于类元数据是在本机内存中分配的,因此最大可用空间是总可用系统内存。 因此,您将不再遇到OOM错误,并可能最终溢出到交换空间中。 最终用户可以选择为类元数据设置最大可用本机空间,或者用户可以让JVM依次增加本机内存以容纳类元数据。
注意 :删除PermGen并不意味着您的类加载器泄漏问题已解决。 因此,是的,您仍然必须监视您的使用情况并做出相应的计划,因为泄漏最终会消耗掉您的整个本机内存,从而导致交换只会变得更糟。
进入元空间及其分配:
现在,Metaspace VM使用内存管理技术来管理Metaspace。 因此,将工作从不同的垃圾收集器移动到仅一个在Metaspace中以C ++执行其所有工作的Metaspace VM。 Metaspace背后的主题很简单,就是类及其元数据的生存期与类加载器的生存期相匹配。 也就是说,只要类加载器处于活动状态,元数据就会在Metaspace中保持活动状态,并且无法释放。
我们一直在宽松地使用“ Metaspace”一词。 更正式地说,每个类加载器的存储区域称为“元空间”。 这些元空间统称为“元空间”。 每个类加载器的元空间回收只能在其类加载器不再活动并且被垃圾收集器报告为已死亡之后才发生。 这些元空间中没有重定位或压缩。 但是会扫描元数据以获取Java引用。
Metaspace VM通过使用分块分配器来管理Metaspace分配。 分块大小取决于类加载器的类型。 有一个全球免费的块列表。 每当类加载器需要一个块时,它都会将其从全局列表中删除并维护自己的块列表。 当任何类加载器死亡时,其块将被释放,并返回到全局空闲列表。 块进一步分为块,每个块保存一个元数据单元。 来自块的块分配是线性的(指针碰撞)。 这些块是在内存映射(映射)空间之外分配的。 有这样的全局虚拟映射空间的链接列表,只要清空任何虚拟空间,它就会返回操作系统。
![](https://i-blog.csdnimg.cn/blog_migrate/fcc8c93db4856bc82a8be316ccc73d31.png)
上图显示了在映射的虚拟空间中具有元块的元空间分配。 类加载器1和3描述了反射或匿名类加载器,它们使用“专用”块大小。 类加载器2和4可以根据这些加载器中项目的数量采用较小或中等的块大小。
元空间调整和工具:
如前所述,Metaspace VM将管理Metaspace的增长。 但是在某些情况下,您可能希望通过在命令行上显式设置-XX:MaxMetaspaceSize来限制增长。 默认情况下,–XX:MaxMetaspaceSize没有限制,因此从技术上讲,元空间的大小可能会增加到交换空间中,您将开始遇到本机分配失败的问题。
对于64位服务器类JVM,–XX:MetaspaceSize的默认/初始值为21MB。 这是最初的高水位线。 一旦达到此水印,就会触发完整的垃圾回收以卸载类(当它们的类加载器不再处于活动状态时),并重置高水印。 高水印的新值取决于释放的元空间的数量。 如果没有足够的空间被释放,则高水位线上升; 如果释放了太多空间,则高水位线将下降。 如果初始水印太低,将重复多次。 您将能够在垃圾收集器日志中可视化重复的完整垃圾收集。 在这种情况下,建议在命令行上将–XX:MetaspaceSize设置为较高的值,以避免初始垃圾回收。
在后续收集之后,Metaspace VM将自动调整您的高水位标记,以便将下一个Metaspace垃圾收集进一步推送出去。
还有两个选项:‑XX:MinMetaspaceFreeRatio和‑XX:MaxMetaspaceFreeRatio。 这些类似于GC FreeRatio参数,也可以在命令行上进行设置。
修改了一些工具以帮助获取有关元空间的更多信息,这些工具在此处列出:
- jmap –clstats <PID> :打印类加载器统计信息。 (现在,它取代了–permstat,后者用于在JDK8之前为JVM打印类加载器统计信息)。 运行DaCapo的Avrora基准测试时的输出示例:
$ jmap -clstats <PID>
Attaching to process ID 6476, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.5-b02
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.liveness analysis may be inaccurate ...
class_loader classes bytes parent_loader alive? type
<bootstrap> 655 1222734 null live <internal>
0x000000074004a6c0 0 0 0x000000074004a708 dead java/util/ResourceBundle$RBClassLoader@0x00000007c0053e20
0x000000074004a760 0 0 null dead sun/misc/Launcher$ExtClassLoader@0x00000007c002d248
0x00000007401189c8 1 1471 0x00000007400752f8 dead sun/reflect/DelegatingClassLoader@0x00000007c0009870
0x000000074004a708 116 316053 0x000000074004a760 dead sun/misc/Launcher$AppClassLoader@0x00000007c0038190
0x00000007400752f8 538 773854 0x000000074004a708 dead org/dacapo/harness/DacapoClassLoader@0x00000007c00638b0
total = 6 1310 2314112 N/A alive=1, dead=5 N/A
- jstat –gc <LVMID> :现在显示元空间信息,如以下示例所示:
![](https://i-blog.csdnimg.cn/blog_migrate/c0f68fd6500bcd6a21646cda20a67010.png)
- jcmd <PID> GC.class_stats:这是一个新的诊断命令,使最终用户能够连接到实时JVM并转储Java类元数据的详细直方图。
注意 :使用JDK8 build 13,必须使用‑XX:+ UnlockDiagnosticVMOptions启动Java。
$ jcmd <PID> help GC.class_stats
9522:
GC.class_stats
Provide statistics about Java class meta data. Requires -XX:+UnlockDiagnosticVMOptions.
Impact: High: Depends on Java heap size and content.
Syntax : GC.class_stats [options] [<columns>]
Arguments:
columns : [optional] Comma-separated list of all the columns to show. If not specified, the following columns are shown: InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total (STRING, no default value)
Options: (options must be specified using the <key> or <key>=<value> syntax)
-all : [optional] Show all columns (BOOLEAN, false)
-csv : [optional] Print in CSV (comma-separated values) format for spreadsheets (BOOLEAN, false)
-help : [optional] Show meaning of all the columns (BOOLEAN, false)
注意 :有关列的更多信息,请参见此处 。
输出示例:
$ jcmd <PID> GC.class_stats
7140:
Index Super InstBytes KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName
1 -1 426416 480 0 0 0 0 0 24 576 600 [C
2 -1 290136 480 0 0 0 0 0 40 576 616 [Lavrora.arch.legacy.LegacyInstr;
3 -1 269840 480 0 0 0 0 0 24 576 600 [B
4 43 137856 648 0 19248 129 4886 25288 16368 30568 46936 java.lang.Class
5 43 136968 624 0 8760 94 4570 33616 12072 32000 44072 java.lang.String
6 43 75872 560 0 1296 7 149 1400 880 2680 3560 java.util.HashMap$Node
7 836 57408 608 0 720 3 69 1480 528 2488 3016 avrora.sim.util.MulticastFSMProbe
8 43 55488 504 0 680 1 31 440 280 1536 1816 avrora.sim.FiniteStateMachine$State
9 -1 53712 480 0 0 0 0 0 24 576 600 [Ljava.lang.Object;
10 -1 49424 480 0 0 0 0 0 24 576 600 [I
11 -1 49248 480 0 0 0 0 0 24 576 600 [Lavrora.sim.platform.ExternalFlash$Page;
12 -1 24400 480 0 0 0 0 0 32 576 608 [Ljava.util.HashMap$Node;
13 394 21408 520 0 600 3 33 1216 432 2080 2512 avrora.sim.AtmelInterpreter$IORegBehavior
14 727 19800 672 0 968 4 71 1240 664 2472 3136 avrora.arch.legacy.LegacyInstr$MOVW
…<snipped>
…<snipped>
1299 1300 0 608 0 256 1 5 152 104 1024 1128 sun.util.resources.LocaleNamesBundle
1300 1098 0 608 0 1744 10 290 1808 1176 3208 4384 sun.util.resources.OpenListResourceBundle
1301 1098 0 616 0 2184 12 395 2200 1480 3800 5280 sun.util.resources.ParallelListResourceBundle
2244312 794288 2024 2260976 12801 561882 3135144 1906688 4684704 6591392 Total
34.0% 12.1% 0.0% 34.3% - 8.5% 47.6% 28.9% 71.1% 100.0%
Index Super InstBytes KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName
目前的问题:
如前所述,Metaspace VM采用了分块分配器。 根据类加载器的类型,有多个块大小。 同样,类项目本身的大小也不固定,因此有可能空闲块的大小可能与类项目所需的块的大小不同。 所有这些都可能导致碎片化。 Metaspace VM尚未使用压缩,因此,碎片化是当前的主要问题。
![](https://i-blog.csdnimg.cn/blog_migrate/666a85c0f61a54e27270802130f937bc.png)
java permgen