8 种 Java- 内存溢出之四 -Metaspace

简介: 8 种 Java- 内存溢出之四 -Metaspace

4.1 java.lang.OutOfMemoryError: Metaspace 概述

Java 应用只允许使用有限的内存. 你的应用可以用的准确的内存大小在启动的时候指定. 展开来说, Java 内存被分成不同的区域, 具体如下图:

所有的这些区域, 包括元空间 (metaspace) 区域, 可以在 JVM 启动的时候指定. 如果你没有指定这些的大小, 平台相关的默认配置会被应用.

java.lang.OutOfMemoryError: Metaspace 消息表明 Metaspace 区内存耗尽.

4.2 原因

如果你不是 Java 领域的新手, 你可能会熟悉 Java 内存管理的另一个叫做: PermGen 的概念. 从 Java 8 开始, Java 的内存模型发生明显改变. 引入一个叫做 Metaspace 的新的内存区域, Permgen 被移除. 这个变更是基于多种原因的, 包括但不限于:

  • PermGen 需要的内存大小难以预测. 它导致有可能由于内存不足触发 java.lang.OutOfMemoryError: Permgen 错误或预留过多导致浪费资源.
  • GC 性能的提升, 在没有 GC 暂停和元数据的特定迭代器的情况下启用并发类数据分配.
  • 支持进一步优化,如 G1 并发类卸载。

所以, 如果你熟悉 PermGen, 那么你需要知道的就是 – Java 8 之前版本在 PermGen 里存在的一切东西(组成类的名字和字段, 方法的字节码, 常量池信息, 对象数组和类型数组, 以及实时编译优化) – 现在都在 Metaspace 里.

如你所见, Metaspace 大小需求取决于加载的类的数量和这些类声明的大小. 所以, 很明显 java.lang.OutOfMemoryError: Metaspace 的主要原因是: 太多类, 或太大的类被加载到 Metaspace 中.

4.3 案例

就如我们在之前解释的那样, Metaspace 使用率与加载到 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();
        }
    }
}
JAVA

在这个例子中, 源代码循环遍历一个循环并在运行时生成类. 所有这些生成的类定义在持续地消耗 Metaspace. javassist库对类生成的复杂性进行了处理.

代码会持续生成新的类, 并加载他们的定义到 Metaspace 中直到空间被完全占满, java.lang.OutOfMemoryError: Metaspace抛出. 当在 Mac OS X, Java 1.8.0_05 上使用 -XX:MaxMetaspaceSize=64m 大概加载 70,000 个类会死掉.

4.4 解决方案

第一个解决因为 Metaspace 内存溢出的方案很明显. 如果应用耗尽了 Metaspace 的内存, 你应该增加 Metaspace 的大小. 调整应用运行配置, 调整下列参数:

-XX:MaxMetaspaceSize=512m

上述配置案例告诉 JVM, Metaspace 允许在抛出 OutOfMemoryError 的错误之前增长到 512MB.

另一个解决方案乍一看更容易. 你可以通过删除这个参数移除 Metaspace 的限制. 但是需要注意的是, 你这么做, 可能会导致 swap 的大量消耗和 / 或导致本机物理内存分配失败.

通过使用上述建议的 “快速修复”, 你只会通过隐藏 java.lang.OutOfMemoryError: Metaspace掩盖症状, 而不是从根本上解决问题.

如果应用程序内存泄漏或是加载的不合理的东西到 Metaspace, 上述解决方案实际上不会改善任何事情, 它只会推迟问题。

相关文章
|
10天前
|
缓存 算法 Java
Java内存管理与调优:释放应用潜能的关键
【4月更文挑战第2天】Java内存管理关乎性能与稳定性。理解JVM内存结构,如堆和栈,是优化基础。内存泄漏是常见问题,需谨慎管理对象生命周期,并使用工具如VisualVM检测。有效字符串处理、选择合适数据结构和算法能提升效率。垃圾回收自动回收内存,但策略调整影响性能,如选择不同类型的垃圾回收器。其他优化包括调整堆大小、使用对象池和缓存。掌握这些技巧,开发者能优化应用,提升系统性能。
|
1月前
|
监控 Java 数据库连接
解析与预防:Java中的内存泄漏问题
解析与预防:Java中的内存泄漏问题
|
2月前
|
存储 缓存 算法
深入剖析Java中JVM的内存模型!!!
对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题。正是因为 Java 程序员把内存控制权利交给 Java 虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会是一个非常艰巨的任务。
45 1
|
2月前
|
存储 缓存 Java
面试官:什么是Java内存模型?
面试官:什么是Java内存模型?
108 0
面试官:什么是Java内存模型?
|
2月前
|
Java Linux
8 种 Java- 内存溢出六 -Out of swap space?
8 种 Java- 内存溢出六 -Out of swap space?
|
2月前
|
存储 Java
java的内存
java的内存需要划分成为5个部分: 1.栈(Stack)存放的都是方法中的局部变量。方法的运行一定要在栈当中运行。 2.堆(Heap)凡是new出来的东西,都是在堆当中 堆内存的东西都有一个地址值:16进制 堆内存的数据,都有默认值。规则: 整数 默认是0 浮点 默认0.0 字符 默认'\u0000' 布尔 默认false 引用类型 默认null 3.方法区(Method Area):存储class相关信息。包含方法的信息 4.本地方法栈(Native Method Stack):与操作系统相关 5.寄存器(pc Register):与cpu相关
27 6
|
6天前
|
缓存 安全 Java
Java并发编程进阶:深入理解Java内存模型
【4月更文挑战第6天】Java内存模型(JMM)是多线程编程的关键,定义了线程间共享变量读写的规则,确保数据一致性和可见性。主要包括原子性、可见性和有序性三大特性。Happens-Before原则规定操作顺序,内存屏障和锁则保障这些原则的实施。理解JMM和相关机制对于编写线程安全、高性能的Java并发程序至关重要。
|
14天前
|
缓存 Java C#
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
56 0
|
2月前
|
存储 安全 Java
一文带你读懂深入理解Java内存模型
java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。可以避免像c++等直接使用物理硬件和操作系统的内存模型在不同操作系统和硬件平台下表现不同,比如有些c/c++程序可能在windows平台运行正常,而在linux平台却运行有问题。 物理硬件和内存
20 1
|
11天前
|
Java
java中jar启动设置内存大小java -jar 设置堆栈内存大小
java中jar启动设置内存大小java -jar 设置堆栈内存大小
11 1