上篇文章,散仙整理了关于JVM的运行时的数据区以及各个区域,本篇我们就来看下各个区域发生异常代码的实战代码,以便于大家更容易在实际应用找到感觉。
1,JAVA堆溢出代码,需要设置JVM参数
生成的dump文件,可以使用Eclipse Memory Analyzer进行分析查看,注意下载的不是eclipse插件,直接可与双击运行的。 下载地址
2,虚拟机栈和本地方法栈溢出
3,方法区和运行时常量池溢出
4,直接内存区异常:
5,String.intern()的使用,看下面例子
1,JAVA堆溢出代码,需要设置JVM参数
- package com.test.jvm;
- import java.util.ArrayList;
- import java.util.List;
- /**
- *
- * 堆异常
- *
- * VM参数
- * -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
- * -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError 生成dump文件
- *-XX:+PrintGCDetails //打印GC日志
- *
- * **/
- public class HeapOOM {
- static class OOMObject{
- }
- public static void main(String[] args) {
- List<OOMObject> oom=new ArrayList<HeapOOM.OOMObject>();
- while(true){
- oom.add(new OOMObject());
- }
- }
- }
- [GC [PSYoungGen: 5066K->817K(5952K)] 5066K->3649K(19648K), 0.0086059 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
- [GC [PSYoungGen: 5937K->816K(5952K)] 8769K->7014K(19648K), 0.0071084 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
- [GC [PSYoungGen: 5936K->832K(5952K)] 12134K->12141K(19648K), 0.0091434 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
- [Full GC [PSYoungGen: 832K->0K(5952K)] [ParOldGen: 11309K->10673K(13696K)] 12141K->10673K(19648K) [PSPermGen: 2492K->2490K(21248K)], 0.1771161 secs] [Times: user=0.25 sys=0.00, real=0.18 secs]
- [Full GC [PSYoungGen: 5120K->0K(5952K)] [ParOldGen: 10673K->13682K(13696K)] 15793K->13682K(19648K) [PSPermGen: 2490K->2490K(21248K)], 0.0549867 secs] [Times: user=0.17 sys=0.00, real=0.06 secs]
- [Full GC [PSYoungGen: 2648K->2599K(5952K)] [ParOldGen: 13682K->13694K(13696K)] 16331K->16293K(19648K) [PSPermGen: 2490K->2490K(21248K)], 0.1501946 secs] [Times: user=0.28 sys=0.00, real=0.15 secs]
- [Full GC [PSYoungGen: 2599K->2595K(5952K)] [ParOldGen: 13694K->13692K(13696K)] 16293K->16287K(19648K) [PSPermGen: 2490K->2490K(21248K)], 0.0715712 secs] [Times: user=0.19 sys=0.00, real=0.07 secs]
- java.lang.OutOfMemoryError: Java heap space
- Dumping heap to java_pid7016.hprof ...
- Heap dump file created [27848402 bytes in 0.106 secs]
- Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
- at java.util.Arrays.copyOf(Arrays.java:2245)
- at java.util.Arrays.copyOf(Arrays.java:2219)
- at java.util.ArrayList.grow(ArrayList.java:213)
- at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:187)
- at java.util.ArrayList.add(ArrayList.java:411)
- at com.test.jvm.HeapOOM.main(HeapOOM.java:30)
- Heap
- PSYoungGen total 5952K, used 2771K [0x00000000ff960000, 0x0000000000000000, 0x0000000000000000)
- eden space 5120K, 54% used [0x00000000ff960000,0x00000000ffc14d28,0x00000000ffe60000)
- from space 832K, 0% used [0x00000000ffe60000,0x00000000ffe60000,0x00000000fff30000)
- to space 832K, 0% used [0x00000000fff30000,0x00000000fff30000,0x0000000000000000)
- ParOldGen total 13696K, used 13692K [0x00000000fec00000, 0x00000000ff960000, 0x00000000ff960000)
- object space 13696K, 99% used [0x00000000fec00000,0x00000000ff95f148,0x00000000ff960000)
- PSPermGen total 21248K, used 2523K [0x00000000f9a00000, 0x00000000faec0000, 0x00000000fec00000)
- object space 21248K, 11% used [0x00000000f9a00000,0x00000000f9c76e98,0x00000000faec0000)
生成的dump文件,可以使用Eclipse Memory Analyzer进行分析查看,注意下载的不是eclipse插件,直接可与双击运行的。 下载地址
2,虚拟机栈和本地方法栈溢出
- package com.test.jvm;
- /**
- * 栈异常
- * 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError
- * 如果虚拟机在扩展栈时无法申请到足够的内存空间,将抛出OutOfMemoryError
- * VM Args:-Xss128k
- */
- public class VMStacSOF {
- public int count=1;
- void add(){
- count++;
- add();
- }
- public static void main(String[] args)throws Throwable {
- VMStacSOF vss=new VMStacSOF();
- try{
- vss.add();
- }catch(Throwable e){
- System.out.println("stack的length: "+vss.count);
- throw e;
- }
- }
- }
- Exception in thread "main" stack的length: 997
- java.lang.StackOverflowError
- at com.test.jvm.VMStacSOF.add(VMStacSOF.java:15)
- at com.test.jvm.VMStacSOF.add(VMStacSOF.java:16)
- at com.test.jvm.VMStacSOF.add(VMStacSOF.java:16)
- at com.test.jvm.VMStacSOF.add(VMStacSOF.java:16)
- at com.test.jvm.VMStacSOF.add(VMStacSOF.java:16)
- at com.test.jvm.VMStacSOF.add(VMStacSOF.java:16)
3,方法区和运行时常量池溢出
- package com.test.jvm;
- import java.util.ArrayList;
- import java.util.List;
- /***
- *
- *
- * 方法区异常
- * -XX:PermSize=3M -XX:MaxPermSize=3M
- *
- * */
- public class MethodAreaOOM {
- public static void main(String[] args) {
- //保持常量引用,避免FULL GC
- List<String> list=new ArrayList<String>();
- int i=0;
- while(true){
- list.add(String.valueOf(i+"fdfd的说法弄得你辅导费多方面的发叫电缆附件的封疆大吏防静电发来的发动静分离定界符多久奋斗飞地方的飞").intern());
- //System.out.println(i);
- i++;
- }
- }
- }
- Exception in thread "Reference Handler" Error occurred during initialization of VM
- java.lang.OutOfMemoryError: PermGen space
- at sun.misc.Launcher$ExtClassLoader.getExtClassLoader(Launcher.java:141)
- at sun.misc.Launcher.<init>(Launcher.java:71)
- at sun.misc.Launcher.<clinit>(Launcher.java:57)
- at java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1486)
- at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1468)
- Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "Reference Handler"
4,直接内存区异常:
- package com.test.jvm;
- import java.lang.reflect.Field;
- import sun.misc.Unsafe;
- /**
- *
- * 直接内存溢出
- * -Xmx20M -XX:MaxDirectMemorySize=10M
- * 切换JDK1.6才有Unsafe这个类,在JDK1.7中不存在此类
- *
- * */
- public class DirectMemoryOOM {
- private static final int _1MB = 1024 * 1024;
- public static void main(String[] args) throws Exception {
- Field unsafeField = Unsafe.class.getDeclaredFields()[0];
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe) unsafeField.get(null);
- while (true) {
- unsafe.allocateMemory(_1MB);
- }
- }
- }
- Exception in thread "main" java.lang.OutOfMemoryError
- at sun.misc.Unsafe.allocateMemory(Native Method)
- at com.test.jvm.DirectMemoryOOM.main(DirectMemoryOOM.java:24)
5,String.intern()的使用,看下面例子
- package com.test.jvm;
- /***
- *
- * String.intern()方法
- * 测试
- * intern()方法,会先从常量池,查找是否在方法区以及存在此对象的
- * 引用,如果存在,就返回,如果不存在,就创建一个新的再放回去
- *
- * **/
- public class TestIntern {
- public static void main(String[] args) {
- String str1=new StringBuilder("我们").append("在这里").toString();
- //这里打印true是因为,常量池不存在,此对象,故把此对象添加进去,然后再取出来,做比较,由于引用地址一样,故为true
- System.out.println(str1.intern()==str1);
- System.out.println("===================================================");
- String str2=new StringBuilder("lon").append("g").toString();
- //这里会输入false,是因为常量池里面已经存在,long ,int,java等字样,与刚创建的实例引用地址不一样,故为false
- System.out.println(str2.intern()==str2);
- }
- }
- true
- ===================================================
- false