JAVA虚拟机调的结构主要由程序计数器,堆,java栈,方法区和本地方法区组成,其中Java栈的作用是在存储某一个方法在被调用的时候的一些信息。程序在启动一个线程的时候都会先给这个线程分配一个栈,线程在调用一个方法的时候会创建一个栈帧,然后将这个栈帧压入到java栈中,当方法调用完后,再将这个栈帧从java栈中取出来释放掉。栈帧中存入有局部变量表,操作数栈,方法出口等信息。
如果程序写的不对,java栈会出现两种错:StatckOverfowError和OutofMemorryError。
StatckOverfowError是请求的深度大于虚拟机java栈的深度时会报这个错误,通俗的说法是一个方法递归调用,不断的调自己,不断的创建栈帧,当所有的栈帧空间大于java虚拟机栈的空间时,就会报这个错误。
OutofMemorryError是当一个新的线程启动后,发现没有多的内存给这个线程分配存储的空间后才会报OutofMemorryError。
总结一下这个错误,相同点都是java栈空间不够了锁导致的,不同点是StatckOverfowError已经给分配线程栈了,但压入的栈帧太多,导致空间不足引起的或者是压入一个栈帧,但是这个栈帧的要求空间太大,一下子就给沾满了导致的。OutofMemorryError是开启一个新的线程后,没有多的空间给这个线程分配了。
下面用两段代码来加深理解
StatckOverfowError
package T20131009;
public class StackOverflowTest {
public static void main(String[] args) {
method();
}
public static void method(){
for(;;)
method();
}
}
OutOfMemoryError
public class StackOverflowErrorMain {
int threadCount = 0;
public StackOverflowErrorMain() {
}
public void addNewThread(){
while (true) {
threadCount++; //线程的数量
new Thread() {
@Override
public void run() {
while (true) ; //线程执行不能停
}
}.start();
}
}
public static void main(String[] args){
StackOverflowErrorMain sofem = new StackOverflowErrorMain();
try {
sofem.addNewThread();
}catch (Throwable e){
System.out.println(sofem.threadCount);
e.printStackTrace();
}
}
}
注意:
1. 在单线程操作中,无论是栈深度无限增加,还是栈帧(每个方法调用执行时都会在栈中创建一个栈帧,用来存储局部变量,操作数栈,动态链表,方法出口等信息)占的空间太大,都出现的是StackOverflowError
2. 不断创建新的线程的实践中会出现OutofMemoryError的错误
参考文档:http://www.cnblogs.com/stefanking/articles/5434043.html