4年前 (2020-09-07)  爪哇岛 |   抢沙发  1255 
文章评分 1 次,平均分 5.0

metaspace元空间的前世今生

我们都知道在Java8中用元空间取代了PermGen

但有几个问题:

  1. MetaSpace默认是GC收集的吗?
  2. 即使PermGen是通过添加-XX:+CMSClassUnloadingEnabled这样的参数进行GC收集的,那么有什么比PermGen更好的MetaSpace呢?
  3. MetaSpace基于本机内存,所以它将java对象保存在磁盘上,而不是VM上?
  4. 甚至元空间也会耗尽内存?如果是这样的话,我将摆脱记忆异常。
  5. 默认情况下,元空间可以随着内存的增加而增长?

 

MetaSpace默认是GC收集的吗?

是的,

GC将在metaspace满时运行,它还将动态增加(如果允许的话)为元数据分配的内存。

 

即使PermGen是通过添加-XX:+CMSClassUnloadingEnabled这样的参数进行GC收集的,那么有什么比PermGen更好的MetaSpace呢?

改进在于元空间的动态扩展,这是permgen无法做到的。

 

MetaSpace基于本机内存,所以它将java对象保存在磁盘上,而不是VM上?

根据metaspace的描述,它只使用本机内存(不分页)。

根据Pierre-Hugues Charbonneau的研究,很明显,引入元空间并不一定能解决OOM问题,它充其量只是解决问题的一种方法,它试图动态地调整元空间内存的大小,以适应不断增加的类,这些类的加载可能会带来不可控增长的副作用(只要本机内存允许)。

我们可以通过将MaxMetaspaceSize参数设置为JVM并运行提供的示例程序来实现著名的OOM错误。

 

GC会用完堆是正常的吗?

是的,GC将在metaspace满时运行,它还将动态增加(如果允许的话)为元数据分配的内存。

有GC的想法是为了防止。。但它可能会接近满,然后GC就会启动。。但这可以通过智能内存配置和合理的编码来防止。。同时拥有大量的RAM可以延长不可避免的时间:)

改进在于元空间的动态扩展,这是permgen无法做到的。你是说permgen不能扩展而元空间可以扩展吗?两者都可以通过提供参数加以限制。那么为什么元空间是可扩展的呢?

如果不指定元空间的上限,它将根据需要(并且可能)扩展。

从我自己的角度来看,它似乎不是GCd,除非它达到了极限,所以有必要为长时间运行的进程设置一个合理的限制。

默认情况下,如果元空间内存达到MaxMetaspaceSize,则收集该内存。此参数最初是无限的。限制是你机器的内存。但当不再需要类和类装入器时,内存会自动释放。只有在怀疑类加载器存在内存泄漏时,才需要调整此参数。

元规范使用本机内存,内存中的组织和指针使得GC比旧的PermGen内存更快。

不,这意味着JVM像普通C程序一样使用内存,而不为java对象使用虚拟内存空间。看来内存只受机器的限制。注意,如果需要,可以将机器的内存交换到磁盘。

如果设置参数MaxMetaspaceSize,则可以从内存中获取;如果不设置此参数,则可以获取进程是否分配了所有计算机内存(包括交换空间)。

metaspace元空间的前世今生

如果达到MetaspaceSize而不是MaxMetaspaceSize,Metaspace绝对不会进行交换(在64位Linux上的java8u60上测试)。一旦发生泄漏,它可以推动其他所有设备进行交换,从而使机器停止运行。

我刚刚测试过,如果Metaspace达到MaxMetaspaceSize而不是MetaspaceSize,那么默认情况下会收集Metaspace。

Java元空间可以交换。显然,如果它被广泛使用,那么其他应用程序的内存将被交换。”“直接记忆”可能会被误解,其含义取决于语境。这里的意思是“不是java虚拟内存,而是os内存”。但在RAM和交换中分配的是“操作系统虚拟内存”。在Linux中,只有特权用户可以直接在RAM中分配内存(参见kmalloc)。JAVA是一个userland进程(它利用了mmap)。

在实践中,我的Linux服务器由于一些元空间(即类/加载器)泄漏而多次停机。在Linux中,用户端程序可以固定虚拟内存,使其始终保持在RAM中。我的16GB的类没有被广泛使用,而且是由非根用户分配的,但是没有一个字节被交换出去。操作系统的重要部分在压力下被换掉了,这导致了中断。

 

MetaSpace默认是GC收集的吗?

一旦类元数据使用量达到“MaxMetaspaceSize”,默认情况下为“unlimited”,就会触发死类和类加载器的垃圾收集,因此需要进行适当的监视以限制此类GC的延迟或频率。

即使PermGen是通过添加-XX:+CMSClassUnloadingEnabled这样的参数进行GC收集的,那么有什么比PermGen更好的MetaSpace呢?

主要目标是删除permgen was,这样用户就不必考虑如何正确地调整它的大小。

MetaSpace基于本机内存,所以它将java对象保存在磁盘上,而不是VM上?

磁盘不是本机内存,而是存储设备。本机内存,在这个上下文中是区域,是Java堆中剩余的进程内存

甚至元空间也会耗尽内存?

是的,它受机器内存量的限制。 metaspace元空间的前世今生

在java7之前,JVM内存中有一个称为PermGen的区域,JVM用来保存它的类。在Java8中,它被移除并被称为元空间的区域所取代。

PermGen和Metaspace之间最重要的区别是什么?

区别是java.lang.OutOfMemoryError:PermGen空间不能再被抛出,VM参数MaxPermSize被忽略。

从用户角度来看,主要的区别是Metaspace默认自动增加其大小(达到底层操作系统提供的大小),而PermGen总是有固定的最大大小。您可以使用JVM参数为Metaspace设置一个固定的最大值,但不能使PermGen自动增加。

在很大程度上,这只是换个名字而已。早在PermGen被引入时,还没有javaee或动态类(un)加载,所以一旦一个类被加载,它就被困在内存中,直到JVM关闭,从而永久生成。现在,类可能在JVM的生命周期内被加载和卸载,因此元空间对于保存元数据的区域更有意义。

它们都包含java.lang.Class实例和它们都受到类加载器泄漏的影响。唯一的区别是,使用Metaspace默认设置,在您注意到症状之前需要更长的时间(因为它会自动增加尽可能多的值),也就是说,您只需将问题推得更远而没有解决它。因此,我认为耗尽操作系统内存的影响可能比jvmpermgen耗尽更严重,因此我不确定这是否有多大的改进。

无论是在PermGen还是Metaspace中使用JVM,在进行动态类卸载,都应该采取措施防止类加载器泄漏,例如使用类加载器泄漏预防库。

Permgen和Metaspace都不包含类类的实例。它们只保留加载类的元信息。类类的实例像其他类的实例一样保存在常规堆中。

Metaspace垃圾收集-一旦类元数据使用量达到MaxMetaspaceSize,就会触发死类和类加载器的垃圾收集。

存储的空间元数据不再与Java堆相邻,元数据现在已移动到本机内存中的一个称为Metaspace的区域。

简单地说,

由于类元数据是从本机内存中分配的,所以最大可用空间是可用系统内存的总和。因此,您将不再遇到OOM错误,并可能最终溢出到交换空间中。

删除PermGen并不意味着类装入器泄漏问题就消失了。所以仍然需要监视您的消耗并相应地进行计划,因为泄漏将最终消耗您的整个本机内存。

简言之,如果不受-XX:MaxMetaspaceSize的限制,元空间大小会根据加载类元数据的需要在本机内存中自动增加

关于metaspace元空间泄露问题的排查可以参考这篇:https://javakk.com/160.html

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/369.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册