4年前 (2020-09-20)  爪哇岛 |   抢沙发  3306 
文章评分 0 次,平均分 0.0

Java应用程序只允许使用有限数量的内存。特定应用程序可以使用的确切内存量是在应用程序启动期间指定的。为了使事情更复杂,Java内存被分成不同的区域,如下图所示:

元空间metaspace内存溢出OutOfMemoryError

所有这些区域(包括元空间区域)的大小可以在JVM启动期间指定。如果您自己不确定大小,将使用特定于平台的默认值。

这个java.lang.OutOfMemoryErrorMetaspace消息表示内存中的元空间区域已用尽。

是什么引起的OutOfMemoryError

如果您不是Java领域的新手,那么您可能熟悉Java内存管理中的另一个概念PermGen。从Java8开始,Java中的内存模型发生了显著的变化。引入了一个称为元空间的新内存区域,并删除了Permgen。这一变化是由于各种原因造成的,包括但不限于:

  • 所需的permgen的大小很难预测。这导致了要么是拨备不足触发java.lang.OutOfMemoryError:Permgen大小错误或过度配置导致资源浪费。
  • GC性能改进,支持并行类数据的取消分配,而无需GC暂停和元数据上的特定迭代器
  • 支持进一步的优化,比如G1并发类卸载。

Java8:从永久代PermGen到元空间Metaspace:https://javakk.com/421.html

因此,如果您熟悉PermGen,那么作为背景,您只需要知道-java8之前PermGen中的内容(类的名称和字段、带有方法字节码的类的方法、常量池、JIT优化等)现在都位于元空间中。

如您所见,元空间大小要求既取决于装入的类的数量,也取决于此类声明的大小。所以很容易看出java.lang.OutOfMemoryErrorMetaspace是:加载到Metaspace的类太多或太大。

给我举个例子

元空间metaspace内存溢出OutOfMemoryError

正如我们在上一章中所解释的,元空间的使用与加载到JVM中的类的数量密切相关。以下代码是最直接的示例:

public class Metaspace {
  static javassist.ClassPool cp = javassist.ClassPool.getDefault();

  public static void main(String[] args) throws Exception{
    for (int i = 0; ; i++) { 
      Class c = cp.makeClass("eu.plumbr.demo.Generated" + i).toClass();
    }
  }
}

在本例中,源代码迭代循环并在运行时生成类。所有这些生成的类定义最终都会消耗元空间。类生成的复杂性由javassist库处理。

在生成新的代码之前,元空间和加载空间将被完全利用java.lang.OutOfMemoryError:抛出Metaspace。当以-XX:MaxMetaspaceSize=64m启动时,在Mac OS X上,我的Java 1.8.0_05会在大约70000个类的加载下消亡。

解决办法是什么?

当面对元空间导致的OutOfMemoryError时,第一个解决方案应该很明显。如果应用程序耗尽内存中的元空间区域,则应增加元空间的大小。更改应用程序启动配置并增加以下内容:

-XX: MaxMetaspaceSize=512m

上面的配置示例告诉JVM在开始以OutOfMemoryError的形式抱怨之前,允许Metaspace增长到512MB。

另一种解决方案乍一看甚至更简单。通过删除此参数,可以完全取消对元空间大小的限制。但是请注意这样做可能会引入大量交换或到达本机分配失败。

不过,在结束这一晚之前,请注意——通常情况下,通过使用上述推荐的“快速修复”,您最终会通过隐藏java.lang.OutOfMemoryError:Metaspace,而不解决根本问题。如果您的应用程序泄漏内存或只是将一些不合理的东西加载到Metaspace中,上述解决方案实际上不会改善任何东西,它只会推迟问题的发生。

 

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

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册