作为一个 Java 为主语言的程序员,我偶尔也需要 用 C/C++ 写程序,在使用时让我很烦恼的一件事情就是需要对 new 出来的对象进行 delete/free 操作,我老是担心忘了这件事情,从而导致内存泄漏或溢出。所以,使用Java让我感觉很爽。但理解 Java 的内存区域是很有必要的。对于 Java 的内存,我们大多数的时候都只是在说堆内存(Heap)和栈内存(Stack),但 Java 内存区域的划分实际上更细,了解它可以让我们进一步的去了解这门语言。

运行时数据区

以下为 Java 运行时数据区的图。

盗图一张,如有侵权,请联系我删除,谢谢!

程序计数器

程序计数器可以看做是当前线程所执行字节码的行号指示器。字节码就是 「.class」 文件中一堆16进制的字节。字节码解释器通过更改程序计数器的值来选取下一条需要执行的字节码指令,分支、循环异常处理等也需要依赖此进行。其是线程独立的,每个线程都有一个。

如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,这个计数器值则为空(Undefined)。

Java虚拟机栈

简介

虚拟机栈描述的是 Java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame[1])用于存储局部变量表、 操作数栈、 动态链接、 方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。也就是说,当退出相应作用域之后,栈中的内存空间就释放掉了。其中,与我们关系最大的当属于局部变量表。

局部变量表

局部变量表是我们平时接触的最多的,很多时候我们会把它与虚拟机栈等同起来,但其实它只是一大部分而已。

局部变量表存放的内容

局部变量表中存放了编译期可知的八种基本数据类型、对象引用(它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和 returnAddress 类型(指向了一条字节码指令的地址)

局部变量表的大小

局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小

局部变量表相关异常

如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

本地方法栈

本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚

拟机使用到的Native方法服务。

Java堆

简介

Java堆(Java Heap)是 Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就

是存放对象实例,几乎所有的对象实例都在这里分配内存。

Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”

大小

Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。

在虚拟机实现时,Java 堆既可以实现成固定大小的,也可以是可扩展的。当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms控制)。 如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出 OutOfMemoryError 异常。

方法区

简介

方法区(Method Area)与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、 常量、 静态变量、 即时编译器编译后的代码等数据。 虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与 Java 堆区分开来。

特点

Java 虚拟机规范对方法区的限制非常宽松,除了和 Java 堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。 相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。 这区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说,这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是必要的。

运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。 Class 文件中除了有类的版本、 字段、 方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。Java虚拟机对Class文件每一部分(自然也包括常量池)的格式都有严格规定,每一个字节用于存储哪种数据都必须符合规范上的要求才会被虚拟机认可、 装载和执行,但对于运行时常量池,Java 虚拟机规范没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。

不过,一般来说,除了保存 Class 文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中[1]。运行时常量池相对于 Class 文件常量池的另外一个重要特征是具备动态性,Java 语言并不要求常量一定只有编译期才能产生,也就是并非预置入 Class 文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是 String 类的 intern() 方法。既然运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出 OutOfMemoryError 异常。

读书笔记-浅析Java运行时数据区的更多相关文章

  1. Jvm基础(1)-Java运行时数据区

    最近在看<深入理解Java虚拟机>,里面讲到了Java运行时数据区,这是Jvm基本知识,把读书笔记记录在此.这些知识属于常识,都能查到的,如果我有理解不对的地方,还请指出. 首先把图贴上来 ...

  2. 【转】Java运行时数据区简介及堆与栈的区别

    理解JVM运行时的数据区是Java编程中的进阶部分.我们在开发中都遇到过一个很头疼的问题就是OutOfMemoryError(内存溢出错误),但是如果我们了解JVM的内部实现和其运行时的数据区的工作机 ...

  3. Java 运行时数据区

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

  4. Java运行时数据区

    目录 1. 概述 2. Java内存结构 3. 程序计数器 4. Java虚拟机栈 5. 本地方法栈 6. 堆 7. 方法区 8. 运行时常量池 9. 直接内存 10. 总结 1. 概述 作为日常的J ...

  5. Java 运行时数据区和内存模型

    运行时数据区是指对 JVM 运行过程中涉及到的内存根据功能.目的进行的划分,而内存模型可以理解为对内存进行存取操作的过程定义.总是有人望文生义的将前者描述为 "Java 内存模型" ...

  6. JVM学习笔记:Java运行时数据区域

    JVM执行Java程序的过程中,会使用到各种数据区域,这些区域有各自的用途.创建和销毁时间.根据<Java虚拟机规范>,JVM包括下列几个运行时数据区域,如下图所示: 其中红色部分是线程私 ...

  7. JVM之Java运行时数据区(线程隔离区)

    来源 JVM会在会在执行Java程序过程中把所管理的内存划分为若干区域,主要包括程序计数器(Program Counter Register),虚拟机栈(VM Stack),本地方法栈(Native ...

  8. JVM内存布局(又叫Java运行时数据区)

    JVM 堆中的数据是共享的,是占用内存最大的一块区域. 可以执行字节码的模块叫作执行引擎. 执行引擎在线程切换时怎么恢复?依靠的就是程序计数器. JVM 的内存划分与多线程是息息相关的.像我们程序中运 ...

  9. JVM之Java运行时数据区(线程共享区)

    JVM运行时区域各线程共享的区域包括堆区和方法区. 堆区 堆区最最主要的功能是存储对象实例[上篇也提到过],因此Java垃圾回收的主要战场就是在堆区,因此也有称为GC堆区.如果堆区的内存不够会出现Ou ...

随机推荐

  1. 【ASP.NET Core】解决“The required antiforgery cookie "xxx" is not present”的错误

    当你在页面上用 form post 内容时,可能会遇到以下异常: The required antiforgery cookie "????????" is not present ...

  2. J2EE和android的GZIP测试

    使用GZIP进行数据压缩传输实验,服务端是J2EE,使用HTTP的POST方式进行数据请求. 为了方便测试,刚开始在J2EE的环境下写了一个TestCase去调用J2EE写的服务,忘记写GZIP解压代 ...

  3. freemaker中的map遍历

    前两天在freemaker中遇到一个问题,怎么遍历一个Map<List<Object>的map呢? 网上找个很多都是类似下面的: <#if map?exists> < ...

  4. HDU - 2612 bfs [kuangbin带你飞]专题一

    分别以两个人的家作为起点,bfs求得到每个KFC最短距离.然后枚举每个KFC,求得时间之和的最小值即可. 此题不符合实际情况之处:  通过了一个KFC再去另一个KFC可以吗? 出题人都没好好想过吗? ...

  5. C语言老司机学Python (三)

    条件语句: 注意1) condition后面的冒号 2) elif if condition_1: statement_block_1elif condition_2: statement_block ...

  6. c#判断外部可执行程序是否已打开(若未打开则打开)

    #region 通过当前代码执行路径向上找到相关exe,并根据processes.Length判断是否已启动 private bool CheckAndOpenExe(string exeName) ...

  7. 嵌入式 视频编码(H264)

    这几天在编写视频录制模块,所以,闲暇之余,又粗粗的整理了一下,主要是API,以备不时之用    摄像头获取的模拟信号通过经芯片处理(我们使用的是CX25825),将模拟信号转成数字信号,产生标准的IT ...

  8. Form提交表单页面不跳转

    1.设计源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...

  9. Java中的i++和i--

    /** * @Title:DataCate.java * @Package:com.you.dao * @Description:数据类型转换 * @Author: 游海东 * @date: 2014 ...

  10. CAN控制器-配置过滤器

    首先简单介绍一下CAN总线,关于CAN总线是谁发明的,CAN总线的历史,CAN总线的发展,CAN总线的应用场合,这些,通通不说.这里只是以我个人理解,简单说说CAN通信.CAN总线的端点没有地址(除非 ...