jvm_内存溢出_虚拟机栈和本地方法栈溢出
来源:互联网 发布:手机实用小五金软件 编辑:程序博客网 时间:2024/06/06 00:41
关于虚拟机栈和本地方法栈,在Java虚拟机规范中描述了两种异常:
- 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
- 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
在实验中,如果将实验范围限制于单线程中的操作,尝试了下面两种方法均无法让虚拟机产生OutOfMemoryError异常,尝试的结果都是获得StackOverflowError异常。
- 使用-Xss参数减少栈内存容量,结果:抛出StackOverflowError异常,异常出现时输出的栈深度相应缩小。
首先设置栈容量参数为-Xss128K
代码:
package jvm;/** * -Xss128K * * @author Poison * */public class JavaVMStackSOF { private int stackLength = 1; public void stackLeak() { stackLength++; stackLeak(); } public static void main(String[] args) { JavaVMStackSOF oom = new JavaVMStackSOF(); try { oom.stackLeak(); } catch (Throwable e) { System.out.println("stack length:" + oom.stackLength); throw e; } }}
运行结果:
stack length:995
Exception in thread “main” java.lang.StackOverflowError
at jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
at jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
……
- 定义了大量的本地变量,增加此方法帧中本地变量表的长度。结果:抛出StackoverflowError异常时输出的栈深度相应缩小。
代码:
package jvm;/** * -Xss128K * * @author Poison * */public class JavaVMStackSOF { private int stackLength = 1; public void stackLeak() { stackLength++; stackLeak(); } public static void main(String[] args) { JavaVMStackSOF oom = new JavaVMStackSOF(); long e0 = 1; long e1 = 1; long e2 = 1; long e3 = 1; long e4 = 1; long e5 = 1; long e6 = 1; long e7 = 1; long e8 = 1; long e9 = 1; long q0 = 1; long q1 = 1; long q2 = 1; long q3 = 1; long q4 = 1; long q5 = 1; long q6 = 1; long q7 = 1; long q8 = 1; long q9 = 1; long r0 = 1; long r1 = 1; long r2 = 1; long r3 = 1; long r4 = 1; long r5 = 1; long r6 = 1; long r7 = 1; long r8 = 1; long r9 = 1; long t0 = 1; long t1 = 1; long t2 = 1; long t3 = 1; long t4 = 1; long t5 = 1; long t6 = 1; long t7 = 1; long t8 = 1; long t9 = 1; long y0 = 1; long y1 = 1; long y2 = 1; long y3 = 1; long y4 = 1; long y5 = 1; long y6 = 1; long y7 = 1; long y8 = 1; long y9 = 1; long u0 = 1; long u1 = 1; long u2 = 1; long u3 = 1; long u4 = 1; long u5 = 1; long u6 = 1; long u7 = 1; long u8 = 1; long u9 = 1; long i0 = 1; long i1 = 1; long i2 = 1; long i3 = 1; long i4 = 1; long i5 = 1; long i6 = 1; long i7 = 1; long i8 = 1; long i9 = 1; long o0 = 1; long o1 = 1; long o2 = 1; long o3 = 1; long o4 = 1; long o5 = 1; long o6 = 1; long o7 = 1; long o8 = 1; long o9 = 1; long p0 = 1; long p1 = 1; long p2 = 1; long p3 = 1; long p4 = 1; long p5 = 1; long p6 = 1; long p7 = 1; long p8 = 1; long p9 = 1; long a0 = 1; long a1 = 1; long a2 = 1; long a3 = 1; long a4 = 1; long a5 = 1; long a6 = 1; long a7 = 1; long a8 = 1; long a9 = 1; long s0 = 1; long s1 = 1; long s2 = 1; long s3 = 1; long s4 = 1; long s5 = 1; long s6 = 1; long s7 = 1; long s8 = 1; long s9 = 1; long d0 = 1; long d1 = 1; long d2 = 1; long d3 = 1; long d4 = 1; long d5 = 1; long d6 = 1; long d7 = 1; long d8 = 1; long d9 = 1; long f0 = 1; long f1 = 1; long f2 = 1; long f3 = 1; long f4 = 1; long f5 = 1; long f6 = 1; long f7 = 1; long f8 = 1; long f9 = 1; long g0 = 1; long g1 = 1; long g2 = 1; long g3 = 1; long g4 = 1; long g5 = 1; long g6 = 1; long g7 = 1; long g8 = 1; long g9 = 1; long h0 = 1; long h1 = 1; long h2 = 1; long h3 = 1; long h4 = 1; long h5 = 1; long h6 = 1; long h7 = 1; long h8 = 1; long h9 = 1; long j0 = 1; long j1 = 1; long j2 = 1; long j3 = 1; long j4 = 1; long j5 = 1; long j6 = 1; long j7 = 1; long j8 = 1; long j9 = 1; long k0 = 1; long k1 = 1; long k2 = 1; long k3 = 1; long k4 = 1; long k5 = 1; long k6 = 1; long k7 = 1; long k8 = 1; long k9 = 1; long l0 = 1; long l1 = 1; long l2 = 1; long l3 = 1; long l4 = 1; long l5 = 1; long l6 = 1; long l7 = 1; long l8 = 1; long l9 = 1; long z0 = 1; long z1 = 1; long z2 = 1; long z3 = 1; long z4 = 1; long z5 = 1; long z6 = 1; long z7 = 1; long z8 = 1; long z9 = 1; long c0 = 1; long c1 = 1; long c2 = 1; long c3 = 1; long c4 = 1; long c5 = 1; long c6 = 1; long c7 = 1; long c8 = 1; long c9 = 1; long v0 = 1; long v1 = 1; long v2 = 1; long v3 = 1; long v4 = 1; long v5 = 1; long v6 = 1; long v7 = 1; long v8 = 1; long v9 = 1; long b0 = 1; long b1 = 1; long b2 = 1; long b3 = 1; long b4 = 1; long b5 = 1; long b6 = 1; long b7 = 1; long b8 = 1; long b9 = 1; long n0 = 1; long n1 = 1; long n2 = 1; long n3 = 1; long n4 = 1; long n5 = 1; long n6 = 1; long n7 = 1; long n8 = 1; long n9 = 1; long m0 = 1; long m1 = 1; long m2 = 1; long m3 = 1; long m4 = 1; long m5 = 1; long m6 = 1; long m7 = 1; long m8 = 1; long m9 = 1; long qq0 = 1; long qq1 = 1; long qq2 = 1; long qq3 = 1; long qq4 = 1; long qq5 = 1; long qq6 = 1; long qq7 = 1; long qq8 = 1; long qq9 = 1; long ww0 = 1; long ww1 = 1; long ww2 = 1; long ww3 = 1; long ww4 = 1; long ww5 = 1; long ww6 = 1; long ww7 = 1; long ww8 = 1; long ww9 = 1; try { oom.stackLeak(); } catch (Throwable e) { System.out.println("stack length:" + oom.stackLength); throw e; } }}
运行结果:
stack length:938
Exception in thread “main” java.lang.StackOverflowError
at jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
at jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
……
实验结果表明:在单个线程下,无论是由于栈帧太大,还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是StackoverflowError异常。
注:Java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
如果测试时不限于单线程,通过不断地建立线程的方式倒是可以产生内存溢出异常,但是,这样产生的内存溢出异常与栈空间是否足够大并不存在任何联系,或者准确地说,在这种情况下,给每个线程的栈分配的内存越大,反而越容易产生内存溢出异常。
原因其实不难理解,操作系统分配给每个进程的内存是有限制的,譬如32位的Windows限制为2GB。虚拟机提供了参数来控Java堆和方法区这两部分内存的最大值。剩余的内存为2GB(操作系统限制)减去Xmx(最大堆容量),再减去MaxPermSize(最大方法区容量),程序计数器消耗内存很小,可以忽略掉。如果虚拟机进程本身耗费的内存不计算在内,剩下的内存就由虚拟机栈和本地方法栈“瓜分”了。每个线程分配到的栈容量越大,可以建立的线程数量自然就越少,建立线程时就越容易把剩下的内存耗尽。
例:
package jvm;/** * -Xss2M * * @author Poison * */public class JavaVMStackOOM { private void dontStop() { while(true){ } } public void stackLeakByThread() { while (true) { Thread thread = new Thread(new Runnable() { @Override public void run() { dontStop(); } }); thread.start(); } } public static void main(String[] args) { JavaVMStackOOM oom = new JavaVMStackOOM(); oom.stackLeakByThread(); }}
注:在Windows平台的虚拟机中,Java的线程是映射到操作系统的内核线程上的,所以上述代码执行时有较大的风险,会使CPU利用率接近100%而导致系统假死。
书上给的运行结果为:
Exception in thread “main” java.lang.OutOfMemoryError: unable to create new native thread
我在测试中未等到出现异常信息机器就近乎卡死了。
- jvm_内存溢出_虚拟机栈和本地方法栈溢出
- 虚拟机栈和本地方法栈溢出
- 虚拟机栈和本地方法栈溢出
- 虚拟机栈和本地方法栈溢出
- 虚拟机栈和本地方法栈溢出
- jvm_内存溢出_本机直接内存溢出
- jvm_内存溢出_运行时常量池溢出
- 【JVM】2_测试虚拟机栈和本地方法栈溢出
- JVM学习笔记-虚拟机栈和本地方法栈溢出
- java虚拟机栈和本地方法栈溢出
- 方法栈和本地方法栈内存溢出异常测试
- jvm_内存溢出_Java堆溢出
- Java虚拟机OOM之虚拟机栈和本地方法栈溢出(4)
- java,内存溢出和栈溢出实例
- jvm_方法区溢出(PermGen Space)
- 【自动内存管理机制】(1)Java内存区域(方法区、虚拟机栈、本地方法栈、堆、程序计数器)与内存溢出异常
- java内存溢出和栈溢出实例以及内存溢出和内存泄露的区别
- java 内存溢出 栈溢出的原因与排查方法
- HUAWEI 3层交换机VLANIF VLAN间路由
- 纪念我的大学生活
- 2.7 缓冲区对象
- 20 迭代器模式
- iOS Https 服务器证书无效
- jvm_内存溢出_虚拟机栈和本地方法栈溢出
- error和Exception有什么区别
- OSG和osgearth显示中文
- Android 高级动画总结(Property Animation)
- java中length属性,length()方法和size()的方法的区别
- 3.11 如何让app使用icon fonts
- ScrollView好用技巧
- MFC消息映射机制(2)
- Git/Repo related cmds