Java内存模型之运行时数据区域

    Java虚拟机会开辟一块内存区域,单独给Java程序使用,这块内存区域又可以分为以下多个部分,如下图1:

     《Java内存模型之运行时数据区域》

图1

    以下表格列出了这些区域的一些特点与区别,如表1:

《Java内存模型之运行时数据区域》

表1


    作用解释:

    程序计算器:用来存贮线程执行当前运行java程序的指令的地址字节码,也就是returnAddress类型。一个线程一个程序计数器;

                         如若当前线程执行的是java方法,则存储指令地址;如若当前线程执行的是Native方法,则存贮的是Undefined;

    Java虚拟机栈:用于存储每个线程所执行的方法的栈帧。每个方法被执行的时候,会同时创建一个栈帧,入栈到Java虚拟机栈;

                             方法执行完毕,则会出栈该栈帧。栈帧中会保存一系列方法中相关的数据,包括局部变量表,操作数栈,动态链  

                             接,方法出口等信息;

                             栈的大小可以由参数-Xss控制;

                             栈帧:方法的调用与完毕,伴随着栈帧的入栈和出栈;栈帧的大小,主要是局部变量表的大小和操作数栈的深度,在编译器就会决 

                                        定;如图2:

《Java内存模型之运行时数据区域》

图2 栈帧图

                             局部变量表:用于存放java虚拟机中10种类型数据(byte,short,int,long,float,double,char,boolean,reference,

                                                  returnAddress);8个基本数据类型数据值都直接存储在栈内,其余两种只是存储引用;内部以slot 

                                                  为单位,除了long,double64位长度需要存储2个slot外,其余都只需要1个slot存储;局部变量表的大 

                                                  小编译的时候固定;

                                                  局部变量表中的slot可以复用,如果某个局部变量生命周期结束了,该slot就可以被该栈帧中下一个定义的局部变量占

                                                  用;

                                                  局部变量表中的变量在类加载的时候没有准备阶段,没有初始值阶段,因此必须声明的时候赋值,不然编译不通过;

                                                  局部变量表的第一个slot存放的是该方法所属对象的引用;可以通过this关键字来调用;

                              操作数栈:  用于方法内部数据运算的存储空间,一次运算的数据往往来源于栈顶的两个元素,出栈运算完毕后入栈结果;因此, 

                                                  在编译阶段和类加载的类校验阶段,必须严格验证指令的数据类型与操作数栈的数据对应匹配;

                              注:当方法调用的时候,如A调用B,一般会把A当前的PC计数器的位置保存在B的栈帧中,当B返回出栈的时候,会让PC计数器指

                                     向B栈帧保存的这个地址;

    本地方法栈:与java虚拟机栈功能一样,只不过它服务与Native方法;

    Java堆:存放对象实例的区域,GC回收器主要作用的地方;堆的大小可以由参数-XMX,-XMS控制;

    方法区:用于存放一些关于类的信息,一些类的变量(非方法实例变量,局部变量),即时编译代码等,其中有一块静态区域,专门用来存放静态变 

                  量和静态代码块;还有方法信息,包括方法表,还有方法体中编译后的字节指令码;它可以选择是否实现垃圾收集;一般垃圾收集不在这

                  个区域,因此也被称为“永久代”;

    运行时常量池(存在于方法区中):存放编译期产生的各种字面量和符号引用;

    直接内存:是处于堆外的内存,被java直接调用,称为直接内存;

    关于内存溢出与栈溢出:

    StackOverflowError:在虚拟机初始化的时候,会给栈分配固定的大小,当线程请求的栈深度大于栈的大小时候,就会抛出该异

                                       常;

    OutOfMemoryError:栈,堆通常可以动态扩展,即在栈深度不够用的时候,可以申请扩展空间大小;当无法再申请到更多的空

                                      间,而又不能满足当前栈或堆空间资源需求的时候,就抛出该异常;

    举例:对于一个语句如 Object object = new Object();这样的对象创建,在内存中有两种方案的内存调用模型,一种为句柄式,一种为直接引用式;

               对于直接引用式来讲,如图3:

《Java内存模型之运行时数据区域》

图3

            对于句柄引用来讲,如图4:

《Java内存模型之运行时数据区域》

图4
          在堆中,对于对象中引用的基本类型数据,基本上会直接存储在堆中,对于如String等引用类型,堆中存储引用,然后值在常量池中。

   

    

    原文作者:java内存模型
    原文地址: https://blog.csdn.net/wangjxy2013/article/details/48847077
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞