此篇是上一篇文章Java内存溢出异常(上)的续篇,没有看过的同学,可以先看一下上篇。本篇文章将介绍剩余的两个溢出异常:方法区和运行时常量池溢出。
方法区和运行时常量池溢出这部分为什么会放在一起呢?在Java内存区域与内存溢出异常这篇文章中我们说过,运行时常量池实际上属于方法区的一部分,所以就放在一起讨论。
常量池溢出
在讨论常量池的溢出之前,先说明一下String.intern()方法,该方法会检查字符串常量池中是否已经包含了一个等于此String对象的字符串,如果已经包含了,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并返回此String对象的引用。看过fastjson源代码的同学应该知道,该方法在fastjson这个json解析库中大量的出现,以提高json的解析速度。
在JDK 1.6之前的版本中,常量池是分配在永久代的,可以通过-XX:PermSize和-XX:MaxPermSize参数来设置大小,从而间接限制其中常量池的容量。
通过以上条件,我们可以轻易的复现这个异常,代码如下:
public class RuntimeConstantPoolOOM { public static void main(String[] args) { List<String> list = new ArrayList<>(); int i = 0; while (true) { list.add(String.valueOf(i++).intern()); } } }