java内存区域与内存溢出异常

概述

    java程序员将内存控制的权利交给了虚拟机,如果不了解虚拟机是如何运行的,那么一旦出现内存泄漏和溢出方面的问题,排查错误将会是一项艰难的工作。

运行时数据区域

    java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干数据区域。这些区域都有各自的用途,以及创建和销毁的时间。java虚拟机管理的内存将会包含以下一个区域:方法区,虚拟机栈,本地方法栈,堆,程序计数器。

程序计数器

    程序计数器是一块较小的内存空间,他可以看作是当前线程所执行的字节码指示器,并且是线程私有的。通过这个计数器的值选择下一条执行的字节码指令。如果线程正在执行的是java程序,那么这个计数器记录的就是正是执行的虚拟机字节码指定的地址,如果是native方法,则这个计数器的值是空(undefined)。此内存区域是唯一一个在java虚拟机规范中没有任何规定OutOfMemoryError情况的区域。

java虚拟机栈(栈内存)

    java虚拟机栈描述的是java方法执行的内存模型,每个方法执行的时候,都会创建一个栈帧。用于存储局部变量表,操作数栈,动态链接,方法出口等信息。java虚拟机栈是线程私有的。java虚拟机规范中定义了两种异常状况:1.StackOverFlowError:如果线程请求的栈深度大于虚拟机允许的深度,将会抛出这个异常;2. OutOfMemoryError如果虚拟机栈可以动态扩展(当前大部分虚拟机栈都可以动态扩展,也有不能动态扩展),如果无法扩展到所需要的内存,就会抛出这个异常。

本地方法栈

    本地方法栈是为虚拟机使用native方法服务。在本地方法栈中没有对方法使用的语言,使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机直接将本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈也会抛出StackOverFlowError和OutOfMemoryError异常。

java堆

    java堆是java虚拟机中所管理的最大的一块内存区域,是所有线程共享的。java堆主要存放的就是对象以及数组。java堆也是垃圾收集器管理的主要区域,有时候也被称为“GC堆”。java堆中还有更细的分类,但是目前不做详细探讨。java堆不是物理上的连续空间,只要逻辑上连续就行了。java堆可以进行扩展,通过-Xmx和-Xms控制。如果堆中没有内存完成实例分配,并且堆也无法扩展的时候,将会抛出OutOfMemoryError异常。

方法区

    方法区也称为永久代,版本名称有各种叫法,不一而足。方法区与java堆一样,是各个线程共享,用于存储已被虚拟机加载的类信息,常量,静态变量,编译后的代码等数据。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

运行时常量池

    运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池存放。运行时常量池具有动态性,不止在编译期才能产生,运行期间也可以将新的常量放进来,这里用的较多的就是string类的intern()方法。由于运行时常量池属于方法区,当无法为常量申请到足够多的内存空间的时候,就会抛出OutOfMemoryError异常。

直接内存

    由于在jdk1.4中引入了NIO类,基于通道(channel)与缓冲区(buffer)的I/O方式。可以使用native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这个内存的引用操作,这样能在一些场景中显著提高性能,因为避免了在java堆和native中来回复制数据。服务器配置管理员会配置-xmx等参数信息,但经常忽略直接内存,使得各个内存区域总和大于物理内存限制,,从而导致动态扩展的时候出现OutOfMemoryError异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值