java8中使用Metaspace就不会出现OOM吗?

关于jvm测试的一些代码我统一整理在了git上,我的git地址为:

https://github.com/wenjieyatou/jvmtest

在java8中,Metaspace的出现,使我们现在不会再遇到java.lang.OutOfMemoryError: PermGen问题,但是我们要记住,这个新特性并不会使类加载导致的内存泄露就此消失。

(一)Metaspace的简单介绍
(1)内存模型:大部分类元数据都在本地内存分配,用于描述类元数据的“klasses“已经被移除。
  (2) 容量:默认情况下只受本地内存限制,但是我们可以限制。

(二)接下来看看Metaspace会不会出现OOM

当我们跑我们的代码:

ClassMetadataLeakSimulator

这个类是不断通过反射来设置创造元数据,在没有对堆栈内存限制的情况下,是可以自动扩充的。可以看出,Metaspace进行了动态扩展,本地内存达到了300多M,加载超过5万个类后还没有出现OOM事件。接下来我们限定一下

但是当我们设置运行参数:

java8中使用Metaspace就不会出现OOM吗?_第1张图片

在执行时,就会出现异常。

ClassMetadataLeakSimulator
Class metadata leak simulator
[GC (Metadata GC Threshold) [PSYoungGen: 173016K->14024K(917504K)] 173016K->14032K(1966080K), 0.1189913 secs] [Times: user=0.25 sys=0.01, real=0.14 secs] 
[Full GC (Metadata GC Threshold) [PSYoungGen: 14024K->0K(917504K)] [ParOldGen: 8K->13933K(1048576K)] 14032K->13933K(1966080K), [Metaspace: 13453K->13453K(1064960K)], 0.2131648 secs] [Times: user=0.50 sys=0.00, real=0.21 secs] 
[GC (Metadata GC Threshold) [PSYoungGen: 110101K->11488K(917504K)] 124034K->25421K(1966080K), 0.0272360 secs] [Times: user=0.03 sys=0.00, real=0.03 secs] 
[Full GC (Metadata GC Threshold) [PSYoungGen: 11488K->0K(917504K)] [ParOldGen: 13933K->25280K(1048576K)] 25421K->25280K(1966080K), [Metaspace: 21815K->21815K(1075200K)], 0.1506802 secs] [Times: user=0.45 sys=0.00, real=0.15 secs] 
[GC (Metadata GC Threshold) [PSYoungGen: 188745K->19296K(917504K)] 214026K->44576K(1966080K), 0.0377606 secs] [Times: user=0.09 sys=0.00, real=0.04 secs] 
[Full GC (Metadata GC Threshold) [PSYoungGen: 19296K->0K(917504K)] [ParOldGen: 25280K->44321K(1048576K)] 44576K->44321K(1966080K), [Metaspace: 35828K->35828K(1089536K)], 0.2502764 secs] [Times: user=0.84 sys=0.02, real=0.25 secs] 
[GC (Metadata GC Threshold) [PSYoungGen: 283121K->32000K(917504K)] 327442K->76321K(1966080K), 0.0621390 secs] [Times: user=0.12 sys=0.00, real=0.06 secs] 
[Full GC (Metadata GC Threshold) [PSYoungGen: 32000K->0K(917504K)] [ParOldGen: 44321K->75904K(1048576K)] 76321K->75904K(1966080K), [Metaspace: 59015K->59015K(1116160K)], 0.3571642 secs] [Times: user=1.17 sys=0.00, real=0.36 secs] 
[GC (Metadata GC Threshold) [PSYoungGen: 235934K->25920K(917504K)] 311839K->101824K(1966080K), 0.0463302 secs] [Times: user=0.14 sys=0.02, real=0.05 secs] 
[Full GC (Metadata GC Threshold) [PSYoungGen: 25920K->0K(917504K)] [ParOldGen: 75904K->101709K(1048576K)] 101824K->101709K(1966080K), [Metaspace: 78076K->78076K(1138688K)], 0.3398833 secs] [Times: user=1.23 sys=0.00, real=0.34 secs] 
[GC (Last ditch collection) [PSYoungGen: 0K->0K(1008128K)] 101709K->101709K(2056704K), 0.0031836 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Last ditch collection) [PSYoungGen: 0K->0K(1008128K)] [ParOldGen: 101709K->95434K(1048576K)] 101709K->95434K(2056704K), [Metaspace: 78076K->78076K(1138688K)], 0.8621092 secs] [Times: user=2.00 sys=0.00, real=0.86 secs] 
ERROR: java.lang.OutOfMemoryError: Metaspace
Done!
Heap
 PSYoungGen      total 1008128K, used 38912K [0x00000000c0000000, 0x0000000100000000, 0x0000000100000000)
  eden space 972800K, 4% used [0x00000000c0000000,0x00000000c2600180,0x00000000fb600000)
  from space 35328K, 0% used [0x00000000fdd80000,0x00000000fdd80000,0x0000000100000000)
  to   space 37888K, 0% used [0x00000000fb600000,0x00000000fb600000,0x00000000fdb00000)
 ParOldGen       total 1048576K, used 95434K [0x0000000080000000, 0x00000000c0000000, 0x00000000c0000000)
  object space 1048576K, 9% used [0x0000000080000000,0x0000000085d32898,0x00000000c0000000)
 Metaspace       used 78084K, capacity 130944K, committed 131072K, reserved 1138688K
  class space    used 12068K, capacity 42536K, committed 42536K, reserved 1048576K

Process finished with exit code 0
可以看出,此时Metaspace被耗尽,将会抛出OOM事件。这里要注意MaxPermSize的区别,MaxMetaspaceSize并不会在jvm启动的时候分配一块这么大的内存出来,而MaxPermSize是会分配一块这么大的内存的。

那么问题来了,如果我们不设置MaxMetaspaceSize,那么我们能用到系统的全部内存吗??
metaspace很可能因为被无止境使用而被OS Kill,所以一般还是设置比较好。

你可能感兴趣的:(JVM)