在购买了一本《深入理解java虚拟机》之后,我便也开始了其中的学习,第一章简单的翻看了一下,从第二章 java内存区域与内存溢出异常来学习。

在第二章的最开头,首先我们知道,在java虚拟机执行java程序时候,会把其管理的内存划分成几个区域,每一个区域都有自己的用途,和创建时间,销毁时间等,这里面的区域划分,有方法区,程序计数器,堆,虚拟机栈,本地方法栈。

其次,分别介绍一下,这几个的作用:

1.方法区:方法区是存放各个线程共享的数据区域,有加载类信息,常量,静态变量,编译后的代码等,但是在JDK1.7的HotSpot中,已经将本身存放在方法区中的字符串常量池移出。

2.程序计数器:此区域,是整个JVM中不会出现内存溢出的区域,为什么会有这个区域的存在呢?是因为我们的程序采用的是调度法,也就是轮流切换的形式。当多个线程在运行,可某一个定点时间只能去运行一个程序,然后来回以高频率的速度去切换,造成给人一种所有程序都是在同时运行的假象,可当一个线程切出去之后,如何能准备的切回来呢?这里就要用到的是程序计数器来控制,他也是每一个线程都私有的一个,互不干扰。

3.推:heap,这个区域我们大家都很熟悉,是存放我们java程序对象的区域,也是最大的一块内存区域,堆这个区域是所有线程都共享的一块区域,里面存放的就是各种对象,数组,同时也是GC最关注的区域,你可以亲切的称呼他为"垃圾堆",哈哈,在垃圾回收上,有各种的机制,新生代,老年代,当然这个区域也是划分了很多,但是无论如何划分,存放的都是对象,无非是划分的细,能更好的回收,这里有一个有意思的是,根据java虚拟机规范中的规定,jvm的堆,在物理上可以是一块不连续的内存空间,只要逻辑上是连续的就行,这块区域可以是固定的,也可以是扩展的,但是现在基本都是可扩展的大小,根据参数(-Xmx  -Xms)控制。

4.虚拟机栈:在老生常谈中,jvm就是方法区,堆,栈,描述的不准确,这个说法也不是很准确,此处的栈,说的就是虚拟机栈stack,首先虚拟机栈,是线程私有的,他的生命周期也是和线程一样的,当线程启动,虚拟机栈创建,线程停止,虚拟机栈销毁。虚拟机栈描述的是java方法执行的内存模型,当方法进栈之后,都会创建一个栈帧的,这里就是用来存储局部变量表,操作数栈,动态链接,方法出口等消息,每一个方法的调用到结束,就意味着一个栈帧在虚拟机中的进栈和弹栈。在局部变量表中存放的有编译期间可以知道的各种基本数据类型,以及对象的引用,和returnAddress类型(指向了一条字节码指令的地址),其中需要注意的是,64位长度的long和double用占据两个局部变量空间,其余的数据类型只会占用一个,另外就是局部变量表在编译期间,就已经知道了内存的大小,当在编译期间,转换字节码的时候,就已经将这个方法所需的内存大小固定下来,在方法运行期间是不会改变这个内存大小的。在栈中,有两种异常信息,第一:线程请求的栈的深度大于了虚拟机允许的深度,就会抛出StackOverflowError异常。第二:当虚拟机要扩展内存时候,无法申请到,会抛出OutOfMenoryError异常。

5.本地方法栈:本地方法栈就和虚拟机栈基本相同,在有个虚拟机中将二者合为其一的也有,如 Sun HotSpot虚拟机就这么做了。唯一的区别就是执行的对象不同,虚拟机栈执行的是字节码服务,但是本地方法栈执行的是虚拟机用到的Native方法服务。