Skip to content

Jvm

程序计数器

程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它的声明周期随着线层的创建而创建,随着线程的结束而死亡。

Java 虚拟机栈

与程序计数器一样,Java 虚拟机栈也是线程私有的,它的生命周期与线程相同,描述的 Java 方法执行的内存模型,每次方法调用的数据都是通过栈传递的。

Java 内存可以粗糙的区分为堆内存和栈内存,其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。(实际上,Java 虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息)

局部变量表主要存放了编译器可知的各种数据类型(booleanbytecharshortintfloatlongdouble)、对象引用(reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其它与此对象相关的位置)

Java 虚拟机栈会出现两种错误:StackOverFlowErrorOutOfMemoryError

  • StackOverFlowError:若 Java 虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 OverOverFlowError 错误。
  • OutOfMemoryError:若 Java 虚拟机堆中没有空闲内存,并且垃圾回收器也无法提供更多内存的话。就会抛出 OutOfMemoryError错误。

Java 虚拟机栈也是线程私有的,每个线程都有各自的 Java 虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。

Java 虚拟机所管理的内存中,Java 堆是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。

Java 世界中“几乎”所有的对象都在堆中国分配,但是,随着 JIT 编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。从 JDK 1.7 开始已经默认开启逃逸分析,如果某些方法中的对象引用没有被返回或者未被外面使用(也就是未逃逸出去),那么对象可以直接在栈上分配内存。

Java 堆是垃圾收集器管理的主要区域,因此也被称为 GC 堆(Garbage Collected Heap)。从垃圾回收的角度,由于现在收集器基本都采用分代垃圾算法,所以 Java 堆还可以细分为:新生代和老年代,再细致一点:Eden 空间、From Survivor、To Survivor 空间等。进一步划分的目的是更好的回收内存,或者更快地分配内存。