Java 内存机制及溢出异常归纳

在java虚拟中执行java程序时,会把执行过程中所管理的内存划分为若干个不同的数据区,这些数据区分别有不同的用途,java虚拟机所管理的内存会划分为以下几个数据区域:

                                      

下面对着几个区域分别进行详细说明:

1. 程序计数器(Program Counter Register)--线程私有

该区域是一块较小的内存,其可以被看作是当前线程所执行的字节码的行号指示器,字节码解释器就是通过改变计数器的值来读取下一条字节码命令,而且分支,循环,跳转,异常处理,线程恢复等都需要依赖该计数器.一个cpu在同一时间只会处理一个线程中的指令,而为了保证java多线程上下文切换正常,需要每条线程都具有一个独立程序计数器,相互独立,不相影响,因此程序计数器的内存是线程私有的。而且其是唯一一个在java虚拟机规范中没有定义OutOfMemory异常的区域

2. java虚拟机栈(java Virtual Machine Stacks)---线程私有

该部分内存生命周期与线程相同,其描述的是java方法执行的内存模型,方法在执行时会在虚拟机栈中创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出入口等信息,方法在调用到结束时,对应栈帧在虚拟机中入栈和出栈过程。

局部变量表存储编译期可知的基本数据类型(4类8种),对象引用类型和returnAddress(指向一条字节码指令的地址),其中64位长度的long和double类型占用2个局部变量空间,其余数据类型占用1个,局部变量表的内存空间在编译期就已经分配完成,在运行期不会发生改变,该区域存在两种异常:

    1) StackOverflowError异常:线程请求的栈深度大于虚拟机所允许的深度;

    2) OutOfMemoryError异常:当虚拟机栈内存扩展时无法申请到足够的内存;

3. 本地方法栈(Native Method Stack)------线程私有

其与虚拟机栈作用类似,区别是虚拟机栈为java方法进行保障,而本地方法栈是虚拟机使用本地方法进行保障,也会抛出StackOverflowError 和 OutOfMemoryError异常;

4. 堆(java heap)------线程共享

其是虚拟机管理内存中最大的一块,同时也是垃圾回收器管理的主要区域,也称GC堆,在虚拟机启动时创建,用于存放对象实例,所有对象实例和数组内存都在java堆中进行分配,java堆可以位于物理上不连续的内存中,只要逻辑连续即可,其大小在虚拟机中使用参数-Xmx和-Xms来控制,当没有内存在存储对象实例且无法扩展时,抛出OutOfMemoryError异常。

5. 方法区(Method Area)------线程共享

用于存储虚拟机加载的信息:类信息,常量,静态变量,即时编译器编译后代码数据等,在HotSpot虚拟机中,GC分代收集扩展到了方法区,实现类似堆内存的管理,在方法区进行内存回收主要是常量池的回收和对类型的卸载,当无法满足内存分布时,出现OutOfMemoryError异常。

6. 运行时常量池---方法区的一部分

其用于存放编译期生成的各种字面量和符号引用,这些内容将在类加载后进行方法区的常量池中进行存放。

 7. java对象的创建及使用

     1) 对象的创建:正常代码中使用new就可以实现对象的创建,虚拟机在碰到new命令时,在虚拟机中具体流程如下:

         (1) 检查指令参数是否在常量池中存在类的符号引用,并检查该符号引用多代表的类是否被加载,解析和初始化过,如果没                有,首先进行类的加载过程;

         (2) 为新对象分配内存,对象所需的内存大小在类加载后就确定了,其在堆上分配内存有两种方式:指针碰撞(内存被分成                使用和为使用两部分,使用的在一端,未使用的在另一端,这种情况分配内存仅需要将指针进行移动即可)和空闲列表              (此时内存中使用和未使用的空间是不连续的,就需要使用一张列表对未使用的内存进行维护记录),具体使用那种分                 配 方式取决于堆内存的情况以,而堆内存的情况又与使用的垃圾收集器有关;除了内存分配方式,当在并发情况下分配               内存时,可能存在线程不安全的情况,解决的方式有两种:采用CAS配上失败重试机制保证更新操作的原子性;把内存               分配划分到不同的空间进行,即在堆中预先分配一块内存(本地线程分配缓冲TLAB),在线程分配内存时,首先在对应线                 程的TLAB中进行分配,只要在TLAB用完时才需要进行同步锁定;

         (3) 在内存分配结束后,将分配到的内存空间初始化为零;

         (4) 虚拟机对对象进行必要的设置,例如对象时哪个类的实例,如何找到类的元数据信息,对象的哈希码,对象的GC分代                  年龄等等;

          (5) 最后执行初始化方法,为对象分配一些初始化数据

      2) 对象存储结构:包含对象头,实例数据,对其补充三个部分。其中,对象头存储对象自身运行时的数据,以及类型指针               (对 象指向对应类元数据的指针,通过其可以确定对象是哪个类的实例);实例数据存储对象真正有效的信息,即代码中定             义的各种类型的字段数据;对齐补充仅起到占位的作用,因为HotSpot虚拟机规定对象的起始地址必须是8字节的整数倍,           所以当对的实例数据没有对齐时,可以使用对齐补充部分进行补充;

      3)对象的访问:在使用对象时,java需要通过栈上的引用来找到具体对象,其具体访问方式目前常见的有句柄和直接指针两             种:使用句柄时,java堆中首先分配一块内存作为句柄池,对象引用中存储的是对象的句柄地址,对象的句柄地址红包含             对象的实例数据和类型数据各种的地址信息,其好处是在对象发生移动时,仅需要改变对象句柄地址中实例对象的指针即             可;令一种方式是使用直接指针访问,好处是速度快;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值