深入JVM 内存区域与OOM 分类:Java编程 Java 与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。 概述: 对于从事C、C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又是执行最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任。 对于Java 程序员来说,不需要在为每一个 new 操作去写配对的delete/free,不容易出现内容泄漏和内存溢出错误,看起来由JVM 管理内存一切都很美好。不过,也正是因为 Java 程序员把内存控制的权力交给了 JVM,一旦出现泄漏和溢出,如果不了解 JVM 是怎样使用内存的,那排查错误将会是一件非常困难的事情。 VM 运行时数据区域 JVM 执行 Java 程序的过程中,会使用到各种数据区域,这些区域有各自的用途、创建和销毁时间。根据《Java 虚拟机规范(第二版)》(下文称 VM Spec)的规定,JVM 包括下列几个运行时数据区域: 1.程序计数器(Program Counter Register): 每一个 Java 线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令,对于非Native方法,这个区域记录的是正在执行的VM 原语的地址,如果正在执行的是 Natvie 方法,这个区域则为空(undefined)。此内存区域是唯一一个在 VM Spec 中没有规定任何 OutOfMemoryError 情况的区域。 2.Java 虚拟机栈(Java Virtual Machine Stacks) 与程序计数器一样,VM 栈的生命周期也是与线程相同。VM 栈描述的是 Java 方法调用的内存模型:每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表、操作栈、动态链接、方法出入口等信息。每一个方法的调用至完成,就意味着一个帧在 VM 栈中的入栈至出栈的过程。在后文中,我们将着重讨论 VM 栈中本地变量表部分。 经常有人把 Java 内存简单的区分为堆内存(Heap)和栈内存(Stack),实际中的区域远比这种观点复杂,这样划分只是说明与变量定义密切相关的内存区域是这两块。其中所指的“堆”后面会专门描述,而所指的“栈”就是 VM 栈中各个帧的本地变量表部分。本地变量表存放了编译期可知的各种标量类型(boolean、byte、char、short、int、float、long、double)、对象引用(不是对象本身,仅仅是一个引用指针)、方法返回地址等。其中 long 和double 会占用2个本地变量空间(32bit),其余占用1个。...