你的位置:首页 > Java教程

[Java教程]Java内存区域与内存溢出


  • 程序计数器

    程序计数器是一块较小的内存,它是线程私有的,可以看作是当前线程执行字节码的计数器。在虚拟机的概念模型中,字节码解释器就是通过这个计数器来找到下一个将要执行的指令。java中分支语句,循环,异常处理以及线程恢复都是通过程序计数器来实现的。

    由于JVM在执行线程的时候是通过CPU轮流执行各个线程的,CPU每次只能执行一个线程的某个指令。这就要求每次在切换线程的时候要能恢复到正确的指令执行位置。因此线程的程序计数器必须是线程私有的。各个线程之间互不影响,独立存储。

    如果该线程正在执行的是一个java方法,则该程序计数器的值就是该方法编译后的正在执行的当前的虚拟字节码的指令位置。如果当前线程执行的是一个native方法,则计数器值为空Undefined。该区域是虚拟机规范中未规定OutOfMemoryError情况的区域。

       

  • 虚拟机栈

    该区域也是线程私有的,并且其生命周期与对应线程生命周期一致。虚拟机栈描述的就是java方法执行的内存模型:每个方法在执行的时候都会在虚拟机栈上建立一个栈帧用来保存局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用就对应着一个栈帧在虚拟机栈中从入栈道出栈的过程。

    我们看到经常有人把内存分为堆内存和栈内存。此处的栈内存就是指虚拟机栈上的局部变量表。局部变量表中存放了编译期可知的各种基本的数据类型,int,float,boolean……以及对象的引用。其中64位长的long和double类型的数会占用两个局部变量存储空间(slot)。其余的均是占用一个。局部变量表所需要的内存空间是编译期间完全确定的。运行期间不会改变大小。在java虚拟机规范中规定里对这个内存区的两种异常情况:如果线程请求的栈深度大于虚拟机允许的最大深度将抛出StackOverflowError.如果虚拟机栈可以动态扩展的话,在扩展的时候无法申请到在足够的内存,则会抛出OutOfMemoryError。

       

  • 本地方法栈

    同上述两个区域一样,该区域也是线程私有区域。它与虚拟机栈发挥的左右是类似的,不同的是虚拟机栈是为java方法服务的,而本地方法栈则是为java调用的本地方法服务的。本地方法栈区也会抛出同虚拟机栈相同的两个异常。

       

  • java堆

    java堆内存是在虚拟机启动的时候创建,所有的对象实例都保存在这个区域,包括数组。因此堆内存也是垃圾收集器的主要工作区域。如果从内存回收的角度来看,现在收集器基本上采用的都是分代收集的策略,所以java堆中还可以细分为新生代和老年代。再细致一点的话可以分为:Eden空间,FromSurvior空间,ToSurvior空间等。

       

     -----------------------------------------------------------<未完待续>-------------------------------------------------------------