栈 StackoverFlowError
java的栈存放的是一些基本类型的变量,对象引用,它是线程私有的空间,与线程的生命周期相同,也保存方法的局部变量、部分结果,jvm允许java栈的大小是固定的,如果线程在计算中,请求的栈深度大于最大可用栈深度,则抛出StackoverFlowError。复现代码如下:
package jvm;
public class StackOverflowDemo {
private int count = 0;
private void foo() {
count++;
foo();
}
public static void main(String[] args) {
StackOverflowDemo stackOverflowDemo = new StackOverflowDemo();
for (;;) {
try {
stackOverflowDemo.foo();
} catch (Throwable e) {
System.out.println("count = " + stackOverflowDemo.count);
e.printStackTrace();
return;
}
}
}
}
执行输出:
count = 20454
java.lang.StackOverflowError
at jvm.StackOverflowDemo.foo(StackOverflowDemo.java:9)
怎么修改栈可用最大深度呢?可以用-Xss参数修改栈大小来改变最大可达深度,我们设置成
-Xss1024k
输出结果:
count = 30105
java.lang.StackOverflowError
栈 OutofMemoryError
同样在栈里面会出现OutofMemoryError
package jvm;
public class OutofMemoryErrorDemo {
public static void main(String[] args) {
for (;;) {
try {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (Exception e) {
}
}
}
}).start();
} catch (Throwable e) {
e.printStackTrace();
return;
}
}
}
}
这样输出:
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
一开始写的时候想的是无限创建线程,但是没有sleep,结果代码运行到去洗了个澡都没有报OutOfMemoryError,洗澡的时候想了一下,可能是因为线程创建太多了导致主线程运行机会变少,这样创建的线程数量是有限的,很难达到OutOfMemoryError,于是加个sleep,让主线程一直创建子线程,果然,很有效果,一下子就出现了。
堆 OutofMemoryError
堆存放new出来的对象,所以只要不停的new对象,总会出现OutofMemoryError的。
package jvm;
import java.util.ArrayList;
import java.util.List;
public class OutofMemoryErrorDemo2 {
public static void main(String[] args) {
List<Object> list = new ArrayList<Object>();
while (true) {
list.add(new Object());
}
}
}
输出:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
与jvm堆内存相关的参数是
-Xms128m JVM初始分配的堆内存
-Xmx512m JVM最大允许分配的堆内存,按需分配
常量池 OutOfMemoryError
运行时常量池溢出,在OutOfMemoryError后面跟随的提示信息是“PermGen space”方法去用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。当前很多主流框架,如spring、hibernate,在对类进行增强时,都会使用到GGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载入内存。
这一类异常一时半会也不好测试,而且在jdk 1.8之后也移除了这块。
网友评论