前言

相信学习过C/C++的朋友们肯定对指针这个概念印象深刻,有了指针,我们就可以随意操作分配给程序的这一块内存,此时此刻内存就是恕瑞玛,程序员就是黄鸡,可以主宰内存里的一切。

但与此同时,权力的代价就是我们需要花费更多的精力在内存管理上,规定某些变量何时生何时死。很明显,这大大增加了一个大型的C/C++系统中程序员的工作量。

在Java中,指针这个概念被删除了,和它有着类似作用的是一个叫做引用的东西,同时引入了Java虚拟机(Java Virtual Machine),这可是个好东西,有了JVM后,程序员不用在内存管理上再亲历亲为了,内存泄露和溢出的问题也减少了很多(计算机永远不会错!)

但是问题的减少不代表问题就此消失,如果不了解JVM的话可能无法很好的排查错误,所以用这一篇文章来介绍一下JVM内存中的各个区域

下面会一个个介绍这些区域的作用

程序计数器 PCR

程序计数器其实就是字节码解释器工作时使用的一个标志,它标志了当前进行到哪个行号了,是程序控制流的指示器。在Java多线程开发的时候,每个线程都分配了一块内存,不同线程之间来回切换,为了从A线程切换到B线程再切换回A线程时可以定位到之前执行的位置,每个线程都被分配了一个PCR。这个内存区域不会有任何OutOfMemoryError的情况。如果线程执行一个Java方法,那么PCR记录的时虚拟机字节码的地址,如果是本地方法,那么计数器的值为Undefined

Java 虚拟机栈 VM Stack

Java虚拟机栈也是线程私有的,它描述的是Java方法执行的线程内存模型,在我们使用.run方法的时候,不同线程之间都有自己的一个栈帧用来存储局部变量表,操作数栈,动态连接,方法出口等,这块学过计算机系统的朋友应该都很熟悉了。

VM Stack中存放了编译期可知的各种基本数据类型,对象引用和returnAddress,这些数据类型在局部变量表以局部变量槽表示。局部变量表所需要的内存空间在编译期完全确定,也就是说,进入一个方法后,这个方法需要在它的栈帧中分配多大的局部变量表是完全确定的。这里的“大小”值的是变量槽的数量,虚拟机最后使用了多大的空间因不同版本的虚拟机而异。

这个内存区域会发生两类异常,一个是线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError,如果Java虚拟机栈容量允许动态扩展,当拓展到极限的时候会抛出OutOfMemoryError

本地方法栈

本地方法栈和VM Stack的作用基本相同,区别在于VM Stack是为Java方法服务,本地方法栈为本地方法服务,也会有上述的两种异常。

Java 堆

Java堆是虚拟机所管理的内存中最大的一块,被所有线程共享,这个区域存在的唯一目的就是存访对象的实例,Java程序中几乎所有的对象实例都在堆上分配内存。不过由于技术(即时编译,逃逸分析,标量替换)的进步,可能以后并不是所有的Java对象实例都会在堆上被分配。

同时,Java堆还是GC(Garbage Collected)管理的内存区域,由于现代垃圾收集器大部分都是基于分代收集理论设计的,所以java堆中经常出现“新生代”,“老年代”等名词。

从分配内存的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer)来提升对象分配时的效率。

TLAB的能够让每个Java线程能使用自己专属的分配指针来分配空间,均摊对Java堆里共享的分配指针做更新而带来的同步开销,这个内容会用一篇新的文章来讲,这里就不继续展开了。

但是无论如何划分,Java堆中存储内容的共性不会被改变,无论哪个区域,存储的都是对象实例,划分是为了更快的分配内存和更好的回收。

Java堆可以处于物理上不连续的内存空间中,但是逻辑上它是连续的,就像磁盘一样,但是对于体积较大的对象,从效率和简单的角度出发,虚拟机会将它们放在连续的空间中,这里涉及到Cache的内容,计算机专业的朋友对这个应该比较熟悉。

在主流的JVM中,Java堆的大小是可拓展的,可以通过参数-Xmx和-Xms设置,当堆无法再扩展且还有对象实例需要分配的时候,JVM会抛出OutOfMemoryError异常。

方法区

方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

对于HotSpot虚拟机来说,在JDK 6之前,运行时常量池是方法区的一部分,同时方法区里面存储了类的元数据(变量名,方法名,访问权限等),即时编译器编译后的代码(比如spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等)等。

JDK 7之后,运行时常量池就被移出去了。到了JDK 8,HotSpot完全废除了方法区上的永久代,(JDK 8以前,HotSpot将GC使用永久代来实现方法区,因为容易造成内存溢出),在本地内存中实现了元空间,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移动到了元空间中

元空间使用的是与堆不相连的本地内存区域,所以理论上系统内存有多大,元空间就有多大,不会出现永久代存在时的内存溢出问题。后面也会专门用一篇文章来介绍元空间的。

运行时常量池

Class文件中有一项是常量池表,用来存放编译器生成的各种字面量与符号引用,字面量包括了文本字符串,final,基本数据类型和其他,符号引用包括了类和结构的完全限定名,字段,方法的名称和描述符等。

这部分内容将会在类加载后存放到方法区的运行时常量池中。运行时常量池相对于Class文件常量池具有动态性,并非预置入Class文件常量池的内容才能进入运行时常量池,运行期间的新的常量也可以,一个栗子就是String类的intern()方法

直接内存

在JDK 1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。

参考[1] 深入理解Java虚拟机,周志明

java数据区_Java运行时数据区域介绍相关推荐

  1. java虚拟机之一内存运行时数据区域解释

    Java虚拟机管理的内存运行时数据区域解释 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启 ...

  2. Java 虚拟机学习笔记 | 运行时数据区总结

    前言 要想学习好 Java,Java虚拟(JVM)的学习是绕不开的.学习 Java虚拟(JVM)首先就要先了解的就是Java虚拟(JVM)运行时数据区. 在Java语言和虚拟机规范中对运行时数据区进行 ...

  3. Java JVM内存模型(运行时数据区域)详解

    详细介绍了JVM运行时数据区域,包括方法区.堆空间.栈空间.本地方法栈.程序计数器.常量池.直接内存.字面量.符号引用.直接引用. Java程序在运行时,需要在内存中的分配空间.为了提高运算效率,ja ...

  4. java执行内存_java运行时内存

    运行时数据区域 java运行时数据区域主要分为下面几个: 方法区 虚拟机栈 本地方法栈 堆 程序计数器 java运行时数据区域.jpg 程序计数器 它是一块较小的内存空间,可以看做是当前线程所指定的字 ...

  5. java 指定 内存_java 运行时指定内存大小

    java -jar -Xms1024m -Xmx1536m -XX:PermSize=128M -XX:MaxPermSize=256M XXX.jar java  -Xms128M -Xmx512M ...

  6. 【JVM】运行时数据区介绍,程序计数器和虚拟机栈详解

    JVM越来越是Java面试中的重头戏,今天来总结一下JVM运行时数据区的相关内容. 文章目录 JVM运行时数据区 JVM运行时数据区内部结构 程序计数器(PC寄存器) 程序计数器的介绍 PC寄存器的实 ...

  7. Java8 JVM运行时数据区概述 (极其详细长文)

    文章目录 运行时数据区概述 JVM中的线程说明 PC寄存器(PC Register) PC寄存器介绍 使用举例 问题:使用PC寄存器存储字节码指令地址有什么用?为什么使用PC寄存器存储? 问题:为什么 ...

  8. 面试回答,JVM内存模型/内存空间:运行时数据区

    发布于个人公众号,打开微信,搜索MelodyJerry即可 本文由作者原文 [JVM|内存模型] Java虚拟机的内存模型?也就这7个而已 修改而来,可点击左下角阅读原文. JVM内存模型/内存空间 ...

  9. JVM运行时数据区---方法区(前言)

    运行时数据区-方法区 方法区内部结构 方法区的演变和垃圾回收 前言 方法区是运行时数据区的最后一个部分. 从线程共享与否的角度来看: ThreadLocal:如何保证多个线程在并发环境下的安全性?典型 ...

  10. JVM初学之JVM的运行时数据区

    什么是JVM的运行时数据区: 看下图: java虚拟机在该虚拟机进程运行过程中定义了各种各样的运行时数据区.用于存储java程序运行时各种不同的数据.有些运行时数据区是在java虚拟机进程开始时就创建 ...

最新文章

  1. 3分钟快速实现:9种经典排序算法的可视化
  2. 调试H3C MSR 20-20 PPPOE拨号
  3. OSChina 周一乱弹 —— 把朋友圈的锦鲤全都抓走
  4. tomcat架构Pipeline和valve技术
  5. Android So简单加固
  6. IIS 6.0 401 错误
  7. 生成Geometry
  8. 回归树与基于规则的模型(part1)--if-then语句
  9. commons-fileupload、smartUpload和commons-net-ftp
  10. USACO翻译:USACO 2012 FEB Silver三题
  11. 情况控件Android layout_weight用法图解
  12. Atitit 人工智能体系树 常用技术 2. 知识图谱 知识处理系统 2 知识发现 知识图谱 1. 1.NLP 2 自然语言处理文本处理 1.1. 语言理解 分词 2 抽取 (压缩文
  13. Drupal 主题函数知识
  14. 《单片机原理及应用(魏洪磊)》第六章第11题
  15. 福大计算机课程表,福州大学课程表(非全日制工程硕士研究生2015年周末班公共....doc...
  16. Jquery鼠标点击后变色,点击另一个按钮颜色还原
  17. 【Python数据分析学习笔记Day3】(三)数据分析工具pandas,数据清洗,聚类K-Means
  18. Thread wait和sleep的区别
  19. AD7190之STM32程序
  20. 思科无线实验AC+AP

热门文章

  1. 联想第三季:PC+时代的航母启航?
  2. netmon中解析非1433端口的TDS协议
  3. ruby环境变量的文件读取形式
  4. 22. yii 2 sql
  5. 1.高性能MySQL --- MySQL 架构
  6. php中几个操作函数参数的函数func_num_args() func_get_args() func_get_arg($i)php
  7. 静态HTML模板渲染
  8. js使用的一些实用技巧
  9. PHP 后台程序配置config文件,及form表单上传文件
  10. iOS开发之App间账号共享与SDK封装