- 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加
- 915. Partition Array into Disjoint Intervals 分割数组
- 932. Beautiful Array 漂亮数组
- 940. Distinct Subsequences II 不同的子序列 II
在jvm中,用来控制Metaspace区域内存大小的参数一般有两个:
也就是说,对应一个jvm来说,Metaspace区域的大小是固定的,比如设置为:-XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M
那如果在应用执行的时候,不断的加载类,使得Metaspace区域被很多类放满了,会发生什么情况呢?
我们前面说过,在发生 Full GC的时候,会带着一起回收Metaspace区域的垃圾对象的;所以一旦Metaspace区域满了,此时它也会触发 Full GC,然后尝试回收自己里面的垃圾对象。
这里就有一个问题,Metaspace区域中的类(klass,class文件在jvm里的运行时数据结构),怎么判断它是否为垃圾对象呢?在这里它的判断条件要比Java堆中的实例对象严格很多:
所以当Metaspace满了的时候,就算执行了Full GC,也未必能够回收掉很多它里面的类;当不能回收很多类的时候,jvm还在继续加载类到Metaspace中,那它也没有地方来存这些类了,也就只有发生OOM了。
其实对于日常的项目运行情况来说,Metaspace区域是很少发生OOM的;如果发生了OOM,一般都是以下两个原因:
在上线系统的时候,使用默认参数,没有指定Metaspace区域的大小,导致Metaspace区域只有默认的20M左右;这对于稍微大一点的系统,本身自己就有很多类,还有依赖的一些第三方框架等也有很多类,20M左右的Metaspace很容易就被填满了;
这里再介绍一个查看jvm中默认参数大小的命令:java -XX:+PrintFlagsFinal -version | grep MetaspaceSize
应对这种情况,正常的应用部署上线都需要设置Metaspace大小;小一点的应用设置为 256M,大一点的应用设置为512M,一般都够用了;
在系统代码中用到了一些cglib等技术动态的生成了一些类,如果代码中没有控制好,导致生成的类过多,很容易就把Metaspace填满;
应对这种情况,如果代码中有需要动态生成类,就需要好好检查代码了,注意生成的数量和回收;如果遇到了这种oom也需要再次回来检查代码;
这里先简略介绍一下动态生成类:
我们平常的类,都是自己写出来的后缀为“.java”的代码文件,里面包含了一些 静态变量、实例变量、方法和业务逻辑;
我们自己都能写出来这些类,那肯定也有办法在系统运行的时候,通过程序来动态生成一些这样的类;
一般生成这样的类有两种方式:
具体的实现就不详细介绍了,需要的可以单独去学习这方面的知识。
这里就通过CGLIB动态代理技术来生成类,模拟 Metaspace OOM的场景:
/**
*
* 元数据区内存溢出
*
* jvm options:
* -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
* -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=hprof/metadata-oom
*/
public class MetaspaceOomDemo {
public static void main(String[] args) {
cglibCreate();
}
public static void cglibCreate() {
int count = 0;
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Test.class);
// 这里有个缓存设置
enhancer.setUseCache(false);
enhancer.setCallback((MethodInterceptor)(o, method, objects, methodProxy) -> methodProxy.invokeSuper(o, objects));
Test testProxy = (Test)enhancer.create();
System.out.println("当前创建了 " + (++count) + "个代理类");
}
}
static class Test {
}
}
上面注释里面的jvm参数,重点就是设置Metaspace的大小和 开启oom时打印堆dump的开关。
如果不了解CGLIB的话,就先把Enhancer当做一个实现动态生成代理类的API,这里我们有一个静态内部类Test;
enhancer.setSuperclass(Test.class);
:通过 Enhancer生成的类是Test的子类;
Test testProxy = (Test)enhancer.create();
:生成 Test的动态代理类;
又由于是在一个while(true)的死循环里面,一直生成Test的动态代理类,所以应该很快就会把Metaspace区域填满。
执行代码:
果然看到控制台打印出了OOM,且是 Metaspace区域的OOM;意思就是在创建了511个动态代理类之后,10M的Metaspace区域被填满了,并且无法回收,再继续生成类的时候就会发生OOM。
这里是通过一段代码来模拟Metaspace区域的OOM,其实跟线上环境出现的情况其实也差不多,那出现这种 Metaspace区域的OOM了我们又该怎么解决呢。
在jvm参数中,我们打开了OOM时打印堆dump日志的开关,所以在发生OOM时,肯定会同时生成一份崩溃日志;
有了这个,那我们还是使用前面介绍过的MAT来分析问题:
1、 首先还是查看Overview中的LeakSuspects,因为这里会给出泄漏疑点:![ ][nbsp1];
看到了一个叫 AppClassLoader的 classloader,占据了532.82 KB (39.01%);看见了这么大的这种classloader,有直觉的肯定都猜到了是动态生成类的时候导致的; 2、 再点上面的Details进去看看:;
这里又看到了AppClassLoader下面有一些 com.bgy.jvm.optimize.MetaspaceOomDemo$Test$$EnhancerByCGLIB$$dc2f0932_434
类; 3、 为了确认,我们再看看dominator_tree中:![ ][nbsp3];
这下可以非常确认了,这里面有几百个 EnhancerByCGLIB$$dc2f0932_434 类;
再看见前面的熟悉的你的项目的包名,那你也应该知道了这个问题就是你项目代码导致的;剩下的事情,也就是去排除你项目中的代码问题了。
我写了一个程序来模拟 MetaSpace OOM。但我发现 MetaSpace Size 几乎总是 Used MetaSpace 的两倍。为什么? 我使用标志 -XX:MaxMetaspaceSize
我想知道如何自己引发OutOfMemoryError: Metaspace异常?是不是可以加载很多类,让它们在内存中长期驻留。 最佳答案 继续向 StringBuilder 添加一些文本,直到出现 O
我正在为生产环境优化 JVM 参数,这包括为应用程序设置最大元空间。我在修复此问题时遇到以下问题: 当环境中有多个应用程序时,我是否真的想设置限制? 是否有内置工具(JDK)可以测量元空间的当前利用率
由于 Java 8 中的元空间,我有一个简短的问题。我知道我可以使用 -XX:MetaspaceSize - 参数设置初始大小。但我想知道是否可以将此值配置为最小大小。 我的目标是防止由于 Metas
java.lang.OutOfMemoryError:Metaspace表示为java类元数据分配的本机内存量已过测试。让我们看看如何在独立应用程序和云应用程序中解决这个问题。 在Java 8及更高版
1. Metaspace区是怎么发生OOM的 在jvm中,用来控制Metaspace区域内存大小的参数一般有两个: -XX:MetaspaceSize:Metaspace初始大小; -X
我一直认为垃圾收集器只清除堆,现在我这么认为。 在 java 8 中,permGen 被删除并被 Metaspace 取代。 据我所知,Metaspace 是垃圾收集器(https://stackov
我目前正在调查我们最近遇到的一些元空间不足问题。罪魁祸首之一似乎是在重新部署 WAR 时加载重复的类。在本地尝试,仅使用我们的一个 WARS,通过完全取消部署后的堆转储,我可以看到应用程序创建的大多数
将我们的 Java 应用程序(在 Tomcat 上运行的服务)JRE 从 Java 7 切换到 Java 8 后,我们开始看到 java.lang.OutOfMemoryError: Metaspac
在 Java 7 之前,JVM 内存中有一个名为 PermGen 的区域,JVM 用来保存它的类。在 Java 8它被移除并被称为 Metaspace 的区域所取代。 PermGen 和 Metasp
在我们的 Wildfly 10 应用服务器上,我们将 groovy 用于 jasperreports 和其他类似系统。 一段时间后,jvm(java 8)收到“内存不足:元空间”错误。 同样的问题发生
我在运行 Java cs 应用程序时遇到 OutOfMemoryError。根据错误信息,似乎是在将XML String传输到Java对象时发生错误。 转账代码如下 public static Obj
我的目标是模拟我可以收到此错误的情况。我试过了How to simulate OutOfMemoryError: Metaspace但它没有帮助。 我在配置中设置:-XX:MaxMetaspaceSi
我知道他们在 Java 8 中用 MetaSpace 替换了 PermGen。但我有几个问题: MetaSpace 是否默认进行 GC 收集? 即使是 PermGen 也是通过添加像 -XX:+CMS
我知道他们在 Java 8 中已将 PermGen 替换为 MetaSpace。但我有几个问题: MetaSpace 是否默认被 GC 收集? 连PermGen都是GC收集的,加了-XX:+CMSCl
目前我正在使用 Gradle 5.2.1 配置 Spring boot 2.1 项目。但是我在构建项目时出现内存不足错误并且无法理解确切原因。 请找到随附的日志 Caused by: org.grad
据我了解,JVM 内的 Native Area 完全禁止垃圾收集器使用。 Metaspace 所在的 Native Area 内部。在前面提到的元空间中,我们有常量池、字段和方法数据等区域。 既然 N
Scala IDE Oxygen 2017 年 9 月运行时出现错误“发生错误。请参阅日志文件 ....metaspace.log。” 版本:Scala 代码运行器版本 2.12.3java版本“9.
Java 8 刚启动后就为 Metaspace 保留 1G。这意味着最小元空间大小为 1G。但我将 MetaspaceSize 设置为 300m,MaxMetaspaceSize 设置为 400m。为
在我们在 Jdk 8 上运行的应用程序中,我们使用 VisualVM 来跟踪加载的类的使用情况和元空间的使用情况。 在我们的应用程序运行的某个时间点,我们看到加载的类的数量不再增加,但是当我们的程序运
我是一名优秀的程序员,十分优秀!