Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途、创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随线程的开始和结束而创建和销毁。

Java虚拟机所管理的内存将会包括以下几个运行时数据区域

程序计数器(Program Counter Register)

它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器。

每一条JVM线程都有自己的PC寄存器,各条线程之间互不影响,独立存储,这类内存区域被称为“线程私有”内存

在任意时刻,一条JVM线程只会执行一个方法的代码。该方法称为该线程的当前方法(Current Method)

如果该方法是java方法,那PC寄存器保存JVM正在执行的字节码指令的地址

如果该方法是native,那PC寄存器的值是undefined。

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

Java虚拟机栈(Java Virtual Machine Stack)

与PC寄存器一样,Java虚拟机栈也是线程私有的。每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。

虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 JVM stack 可以被实现成固定大小,也可以根据计算动态扩展。 如果采用固定大小的JVM stack设计,那么每一条线程的JVM Stack容量应该在线程创建时独立地选定。JVM实现应该提供调节JVM Stack初始容量的手段;
如果采用动态扩展和收缩的JVM Stack方式,应该提供调节最大、最小容量的手段。 如果线程请求的栈深度大于虚拟机所允许的深度将抛出StackOverflowError; 如果JVM Stack可以动态扩展,但是在尝试扩展时无法申请到足够的内存时抛出OutOfMemoryError。

本地方法栈(Native Method Stack)

本地方法栈与虚拟机栈作用相似,后者为虚拟机执行Java方法服务,而前者为虚拟机用到的Native方法服务。

虚拟机规范对于本地方法栈中方法使用的语言,使用方式和数据结构没有强制规定,甚至有的虚拟机(比如HotSpot)直接把二者合二为一。

这玩意儿抛出的异常跟上面的虚拟机栈一样。

Java堆(Java Heap)

虚拟机管理的内存中最大的一块,同时也是被所有线程所共享的,它在虚拟机启动时创建,这货存在的意义就是存放对象实例,几乎所有的对象实例以及数组都要在这里分配内存。这里面的对象被自动管理,
也就是俗称的GC(Garbage Collector)所管理。用就是了,有GC扛着呢,不用操心销毁回收的事儿。 Java堆的容量可以是固定大小,也可以随着需求动态扩展(-Xms和-Xmx),并在不需要过多空间时自动收缩。 Java堆所使用的内存不需要保证是物理连续的,只要逻辑上是连续的即可。 JVM实现应当提供给程序员调节Java 堆初始容量的手段,对于可动态扩展和收缩的堆来说,则应当提供调节其最大和最小容量的手段。 如果堆中没有内存完成实例分配并且堆也无法扩展,就会抛OutOfMemoryError。

方法区(Method Area

跟堆一样是被各个线程共享的内存区域,用于存储以被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然这个区域被虚拟机规范把方法区描述为堆的一个逻辑部分,但是它的别名叫非堆,用来与堆做一下区别。

方法区在虚拟机启动的时候创建。

方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。

方法区在实际内存空间中可以是不连续的。

Java虚拟机实现应当提供给程序员或者最终用户调节方法区初始容量的手段,对于可以动态扩展和收缩方法区来说,则应当提供调节其最大、最小容量的手段。

当方法区无法满足内存分配需求时就会抛OutOfMemoryError。

这里有一个小例子,来说明堆,栈和方法区之间的关系的

public class Test2 {
public static void main(String[] args) {
public Test2 t2 = new Test2();
//JVM将Test2类信息加载到方法区,new Test2()实例保存在堆区,Test2引用保存在栈区
}
}

运行时常量池(Runtime Constant Pool

它是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,
这部分内容将在类加载后存放到方法区的运行时常量池中。 Java虚拟机对Class文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。
但对于运行时常量池,Java虚拟机规范没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。不过,一般来说,除了保存Class文件中描述的符号引用外,
还会把翻译出来的直接引用也存储在运行时常量池中。 运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只能在编译期产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,
运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。 既然运行时常量池是方法区的一部分,自然会受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。

直接内存(Direct Memory)

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。

JDK1.4加的NIO中,ByteBuffer有个方法是allocateDirect(int capacity) ,这是一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,
然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。 显然,本机直接内存的分配不会受到Java堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM及SWAP区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,
一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常。

转载自:http://www.cnblogs.com/Cratical/archive/2012/08/21/2649985.html

关于String与常量池的种种,可以参考博文:http://www.cnblogs.com/kkgreen/archive/2011/08/24/2151450.html

【Java虚拟机】运行时数据区的更多相关文章

  1. 《深入理解Java虚拟机》(二)Java虚拟机运行时数据区

    Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第二章 ,为了整理思路,简单记录一下,方便后期查阅. 2.2 运行时数据区域 Java虚拟机 ...

  2. Java虚拟机运行时数据区

    运行时数据区程序计数器Java虚拟机栈本地方法栈Java堆(GC堆)方法区运行时常量池 运行时数据区 Java虚拟机在运行Java程序时,会将它所管理的内存划分为若干个内存区域.这些数据区域有各自的用 ...

  3. 面试常问的 Java 虚拟机运行时数据区

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

  4. Java 虚拟机运行时数据区

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

  5. 【深入理解Java虚拟机】Java虚拟机运行时数据区

    Java虚拟机运行时数据区 线程私有 程序计数器 1.当前线程所执行的字节码的行号指示器. 2.唯一不会发生OutOfMemoryError的区域 3.如果执行的是java方法,计数器值为虚拟机字节码 ...

  6. 笔记:Java虚拟机运行时数据区

    Java虚拟机在执行Java程序的过程中会把它管的内存划分为以下若干个不同的区域: 1.程序计数器 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器:由于Java虚拟机的 ...

  7. 【JVM从小白学成大佬】2.Java虚拟机运行时数据区

    目录 1.运行时数据区介绍 2.堆(Heap) 是否可能有两个对象共用一段内存的事故? 3.方法区(Method Area) 4.程序计数器(Program Counter Register) 5.虚 ...

  8. 【JVM学习】2.Java虚拟机运行时数据区

    来源: 公众号: 猿人谷 这里我们先说句题外话,相信大家在面试中经常被问到介绍Java内存模型,我在面试别人时也会经常问这个问题.但是,往往都会令我比较尴尬,我还话音未落,面试者就会"背诵& ...

  9. Java 虚拟机运行时数据区详解

    本文摘自深入理解 Java 虚拟机第三版 概述 Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟 ...

  10. 深入理解Java虚拟机&运行时数据区

      其中,程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭.

随机推荐

  1. UVa409_Excuses, Excuses!(小白书字符串专题)

    解题报告 题意: 找包括单词最多的串.有多个按顺序输出 思路: 字典树爆. #include <cstdio> #include <cstring> #include < ...

  2. C#中汉字排序简单示例(拼音/笔划)

    可以按照区域语言修改排序规则. class Program { static void Main(string[] args) { string[] arr = { "趙(ZHAO)&quo ...

  3. 去除ArcMap连接空间数据库中多余的属性表

    这个操作目前可能不具有可行性,但是为了完整性还是在下面讲一下吧.如有兴趣的小伙伴,可以按照下面的操作方式去尝试. 一.需求 去除ArcMap连接空间数据库中多余的属性表. PL/SQL中查询得到的内容 ...

  4. Matlab绘图控制命令

    [转载] 图形的控制与表现 (Figure control and representation) MATLAB提供的用于图形控制的函数和命令: axis:  人工选择坐标轴尺寸.     clf: ...

  5. Myeclipse反编译插件(jad)的安装和使用

    在开发过程中我们肯定会遇到这样的问题,当我们调试程序的时候,走到一个地方发现引用了一个第三方的东西,点进去一看,会出现一下的画面,没有源代码!!!! 这让人很头疼,今天给大家介绍一个Myeclipse ...

  6. Android之在应用程序内部关注某人的微信

    Intent intent = new Intent(Intent.ACTION_VIEW); intent.setPackage("com.tencent.mm");//直接打开 ...

  7. WhyDX9:翻写D3D红龙书中的程序

    之前写过一套学习OpenGL的框架:WhyGL,即然有了GL那也应该再写个学习D3D的框架:WhyDX9.两个程序的架构相同,然后这个程序是将D3D红龙那本书的DEMO翻写了一遍.先将可执行程序发一下 ...

  8. 简单MapReduce思维导图

  9. 树行控件TreeView 在WinForm下 怎么实现重命名功能

    public Form1() {     InitializeComponent();     this.Load+=new EventHandler(Form1_Load);     treeVie ...

  10. Loadrunner视频教程汇总

    小布老师视频:测试工具概述,兼LoadRunner介绍 -1-4http://www.boobooke.com/v/bbk1046http://www.boobooke.com/v/bbk1046.z ...