1、java虚拟机栈(java virtual machine stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是java方法执行的内存模型:每一个方法被执行的时候都会同时建立一个栈帧(stack frame)用于存储局部变量表、操做栈、动态连接、方法出口等信息。每个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
常常有人把java内存区分为堆内存(Heap)和栈内存(Stack),这种分法比较粗糙,java内存区域的划分其实远比这复杂。这种流行方式的划分只能说明大多数程序员最关注的、与对象内存分配关系最密切的内存区域是这两块。其中所指的“栈”就是虚拟机栈,或者说是虚拟机栈中的局部变量表部分。
局部变量表存放了编译期可知的各类基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象自己,根据不一样的虚拟机实现,它多是一个指向对象起始地址的引用指针,也可能指向一个表明对象的句柄或者其余与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。
其中64位长度的long和double类型的数据会占用2个局部变量空间,其他的数据类型只占用一个。局部变量表所需的内存空间在编译期间完成分配。当进入一个方法时,这个方法须要在帧中分配多大的局部变量空间是彻底肯定的,在方法运行期间不会改变局部变量表的大小。
在java虚拟机规范中,对这个区域规定了2种异常状况:若是线程请求的栈深度大与虚拟机所容许的深度,将抛出StackOverFlowError异常;若是虚拟机栈能够动态扩展,当扩展时没法申请到足够的内存时会抛出OutOfMemoryError异常。
2、 对于大多数应用来讲,java堆(java Heap)是java虚拟机所管理的内存中最大的一块。Java堆是被全部线程共享的一块内存区域,在虚拟机启动时建立。此内存区域的惟一目的就是存放对象实例,几乎全部的对象实例都在这里分配内存。这一点在java虚拟机规范中的描述是:全部的对象实例以及数组都要在堆上分配,可是随着JIT编译器的发展与逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术将会致使一些微妙的变化发生,全部的对象都分配在堆上也逐渐变得不是那么“绝对”了。
Java堆是垃圾收集器管理的主要区域,所以不少时候也被称为“GC”堆。若是从内存回收的角度看,因为如今收集器基本都是采用的分代收集算法,因此java堆中还能够细分为:新生代和老生代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。若是从内存分配的角度看,线程共享的java堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。不过,不管如何划分,都与存放内容无关,不管哪一个区域,存储的都仍然是对象实例,进一步划分的目的是为了更好的回收内存,或者更快的分配内存。
根据java虚拟机规范的规定,java堆能够处于物理上不连续的内存空间中,只要逻辑上是连续的便可,就像咱们的磁盘空间同样。在实现时,既能够实现成固定大小的,也能够是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的。若是在堆中没有内存完成实例分配,而且堆也没法再扩展时,将会抛出OutOfMemoryError异常。
java