jdk8中的StringTabel是放在堆空间的,我们分析一个案例说明。
public class Jvm1_6 { public static void main(String[] args) { List<String> list=new ArrayList<>(); int i=0; try { for(int j=0;i<20000;j++){ list.add(String.valueOf(j).intern()); } }catch (Throwable e){ e.printStackTrace(); }finally { System.out.println(i); } } }
默认的堆空间比较大,我们需要限制堆空间的大小,加上启动参数:
-Xmx10m
运行结果如下:
java.lang.OutOfMemoryError: GC overhead limit exceeded at java.lang.Integer.toString(Integer.java:401) at java.lang.String.valueOf(String.java:3099) at Jvm1_6.main(Jvm1_6.java:14) 148707
我们发现暂时还看不出是内存溢出,只看到GC超过某限制导致的问题。
这个问题我们通过官网文档查询参数解释如下:
XX:+UseGCOverheadLimit
Enables the use of a policy that limits the proportion of time spent by the JVM on GC before an OutOfMemoryError exception is thrown. This option is enabled, by default and the parallel GC will throw an OutOfMemoryError if more than 98% of the total time is spent on garbage collection and less than 2% of the heap is recovered. When the heap is small, this feature can be used to prevent applications from running for long periods of time with little or no progress. To disable this option, specify -XX:-UseGCOverheadLimit
这里大致的意思是说JVM花费了超过98%的时间确回收 了少于2%的内存,这种情况基本就是崩溃了,这个特性就会被用来阻止应用运行下去了,当然禁用的方法就是-XX:-UseGCOverheadLimit。
我们加上这个选项再运行:
java.lang.OutOfMemoryError: Java heap space at java.lang.Integer.toString(Integer.java:401) at java.lang.String.valueOf(String.java:3099) at Jvm1_6.main(Jvm1_6.java:14) 150453
看到了我们意料之中的堆内存溢出了。