Java 堆栈和OOM、SOF

在介绍堆栈之前简单说下JVM的内存结构,一共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分:

栈:
 线程私有,生命周期和线程生命周期相同;
 栈由一些列帧组成;
 每个方法在创建的执行的时候都会创建一个栈帧,用来存储局部变量、操作数栈、动态链接、方法返回地址等;
 每个方法从调用到执行完毕对应一个栈帧在虚拟机栈中的入栈和出栈

堆:线程共享,在虚拟机启动的时候创建,用来存放对象实例,是GC管理的主要区域

方法区:线程共享,用于存储已被虚拟机加载的类信息、类型的常量池、静态变量、字段和方法信息等

程序计数器:线程私有,是当前线程所执行的字节码行号指示器,每个线程都有一个独立的程序计数器,字节码解释器工作时通过改变它的值来选取下一条需要执行的字节码指令。

本地方法栈:线程私有,主要为虚拟机用到的native方法服务,与虚拟机栈类似

简单描述下堆栈的各自特点:
比较通俗的讲就是栈是用来执行程序的,堆主要是用来存放对象的。栈是一种具有先进后出性质的数据结构,也就是说后存放的先取出。堆是一种经过排序的树形数据结构,每个节点都有一个值。通常所说的堆的数据结构也就是二叉堆。

SOF全称StackOverFlowError是指栈溢出,由上面介绍可知栈是义帧为单位保存线程运行状态的,当线程调用一个方法时JVM会压入一个新的栈帧到这个线程的栈空间中,当方法执行结束时栈帧会出栈,但是在方法执行过程中,这个栈帧会一直存在的。所以如果方法的嵌套调用层次太多,随着栈帧的增加导致总和大于JVM设置的-Xss值就会抛出StackOverFlowError。

OOM全程OutOfMemoryError 可能分为几种情况:

堆内存溢出:当需要为创建的对象实例化分配堆内存空间时,如果此时堆的占用已达到了设置的最大值(通过 -Xmx),就会抛出OutOfMemoryError

方法区内存溢出:在类加载器加载class文件到内存时,JVM会提取类的信息(包括:类名、访问修饰符、常量池、字段描述、方法描述等)到方法区,而此时如果需要存储这些类信息但是方法区的内存占用又已达到最大值,就会抛出OutOfMemoryError

下面给出两个例子可以看下:

  //堆溢出例子OOM
  public void heapException(){  
      for(;;) {  
          ArrayList list = new ArrayList (2000);  
      }
  }

  //栈溢出例子SOF
  int count = 1;  
  public void stackException(){  
      count++;  
      this.stackException();  
  }  

你可能感兴趣的:(Java 堆栈和OOM、SOF)