关于第二版《深入理解java虚拟机》中“栈溢出”案例的不同看法

 2019-12-22 11:26  阅读(1870)
文章分类:JVM

原文:

  • 使用-Xss参数减少栈内存容量。结果:抛出StackOverflowError异常,异常出现时输出的堆栈深度缩小。

  • 定义了大量的本地变量,增大此方法帧中本地变量表的长度。结果:抛出StackOverflowError,异常出现时输出的堆栈深度缩小。 书中代码如下:

    public class JavaVMStackSOF { private int stackLength = 1;

        public void stackLeak() {
            stackLength++;
            stackLeak();
        }
    
        public static void main(String[] args) throws Throwable {
    
            JavaVMStackSOF oom = new JavaVMStackSOF();
            try {
                oom.stackLeak();
            } catch (Exception e) {
                System.out.println("stack length:" + oom.stackLength);
                throw e;
            }
        } 
      }
    

结果:

Exception in thread "main" java.lang.StackOverflowError
        at com.yanming.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
        at com.yanming.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
        at com.yanming.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)

解析:

  • 关于第一点没问题,使用-Xss参数减少栈的内存,确实会导致StackOverflowError。

  • 但是关于第二点,作者说是因为定义的大量的本地变量导致的StackOverflowError,个人却并不这么认为,虽然用递归无限使用stackLength++的操作,但是在stackLength++的同时,之前的stackLength值,由于已经没有地方引用了,会自动回收,所以并不是因为大量本地变量导致的。

  • 我们可以去掉原代码中的变量stackLength,再次输出结果看看:

    public class JavaVMStackSOF {

        public void stackLeak() {
            stackLeak();
        }
    
        public static void main(String[] args) throws Throwable {
    
            JavaVMStackSOF oom = new JavaVMStackSOF();
            try {
                oom.stackLeak();
            } catch (Exception e) {
                throw e;
            }
        }
    }
    
  • 结果:

    Exception in thread "main" java.lang.StackOverflowError at com.yanming.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14) at com.yanming.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14) at com.yanming.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)

  • 可以看到,即使没有本地变量,很快就出现StackOverflowError的异常,这是因为代码中使用到了递归算法,stackLeak()方法无限的压入栈,由于栈的结构先进后出,先压入栈的方法无法释放,导致StackOverflowError。

  • 从另一个角度证明,并不是大量的本地变量导致的StackOverflowError。我们可以将原代码稍微改动下,stackLength++的操作,我们放入while循环中执行,看看有什么结果:

    public class JavaVMStackSOF { private int stackLength = 1;

        public void stackLeak() {
    
            // 无限循环stackLength++;
            while (true) {
                stackLength++;
                System.out.println(stackLength);
            }
        }
    
        public static void main(String[] args) throws Throwable {
    
            JavaVMStackSOF oom = new JavaVMStackSOF();
            try {
                oom.stackLeak();
            } catch (Exception e) {
                System.out.println("stack length:" + oom.stackLength);
                throw e;
            }
        }
    }
    

结果:
2019120001714\_1.png

  • 我们可以看到程序会一直执行下去,并不会出现栈溢出错误。

所以,关于这一点个人认为书中的此案例出现栈溢出的原因是递归方法所知,并不是本地变量所致。

点赞(1)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 关于第二版《深入理解java虚拟机》中“栈溢出”案例的不同看法

相关推荐