之前由于考研,对于虚拟机的认识疏忽了太多,现在重新整理回顾一下。

如上图所示,jvm的内存区域(运行时数据区)共分为5处:方法区(Method Area)、虚拟机栈(vm Stack)、本地方法栈(Native Method Stack)、堆(Heap)和程序计数器(Program Counter Register)

程序计数器:它是一块内存较小的区域,可以看成是线程所执行的字节码的行号指示器,字节码解释器运行时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。在java虚拟机中,多线程的运行采用的的是线程轮流切换机制,所以每条线程都需要建立一个独立的程序计数器,它是线程私有的。

虚拟机栈:它和程序计数器一样,也是线程私有的,它的作用是当java线程运行时,java方法在执行的同时会建立一个栈帧,用来存储局部变量表、操作数栈、动态链接,方法出口等信息。每个java方法从调用到执行完成的过程,就对应着一个栈帧从入栈到出栈的过程。局部变量表所需的内存空间在编译期间分配完成,所以当进入一个方法时,需要在帧中分配多大的局部变量空间是完全确定的(除了long和double类型的数据会占用2个局部变量空间外,其他基本数据类型仅占用1个局部变量空间),在方法运行期间并不会改变局部变量表的大小。如果线程请求的栈深度大于虚拟机的规定,将抛出StackOverFlowError异常;如果虚拟机栈动态扩展时无法申请到足够的内存空间,将会抛出OutOfMemoryError异常。

本地方法栈:它与虚拟机栈所发挥的作用相似,区别就是虚拟机栈为java方法服务,而本地方法栈为Native()方法服务,抛出异常痛上。

java堆:堆(Heap)是java虚拟机所管理内存的内存中最大的一块。java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,存放对象实例。当Heap没有内存可以完成实例分配,而且堆也无法再扩展时,将会抛出OutOfMemoryError异常

方法区:与java堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量和即时编译器编译后的代码等数据。虽然java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它有一个别名Non-Heap(非堆),提醒读者将它与java区分开。java虚拟机堆方法区的限制非常宽松,除了和java堆一样不需要连续的内存空间和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。当方法区无法满足内存分配需求时,将会抛出OutOfMemoryError异常。

此外,还有一个特殊区域——运行时常量池(Runtime Const Pool)是方法区的一部分。除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。另外一个重要特征是具有动态性,java语言并不要求常量一定只有编译器才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用的比较多的便是String类中Intern()方法。

对象的创建

当虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载,如果没有,那必须先执行相应的类加载过程,类加载检查通过后,接下来就虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从java队中划分出来,内存分配完成以后,虚拟机需要将分配到的内存空间都初始化0值(不包括对象头)(这一步操作保证了对象的实例字段在java代码中可以不赋初始值就直接使用),接下来,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例,在上面的工作都完成以后,从虚拟机的视角来看,一个新的对象已经产生了,但从java程序的视角来看,对象创建才刚刚开始——<init>方法还没有执行,所有的字段都为0.

对象的内存布局

在HotSpot虚拟机中,对象在内存中的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

对象头:包括两部分信息,一是用于存储对象自身的运行时数据,如哈希码、GC分代年龄等,官方称为“Mark Word”。二是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例,如果对象是一个数组,那对象头中还必须有一块记录数组长度的数据。

实例数据:对象真正有效的信息,也是在程序代码中所定义的各种类型的字段内容。无论是来自父类还是子类,都需要记起来。这部分的存储顺序会受到虚拟机分配策略参数(FieldsAllocationStyle)和字段在Java源码中定义顺序的影响。

对齐填充:占位符,并非必然存在,没有特别的含义。

对象的访问定位

java程序需要通过栈上的reference数据来操作堆上的具体对象。java虚拟机规范中只规定reference类型只是一个指向对象的引用,并没有规定这个引用应该通过何种方式定位、访问堆中的对象的具体位置,所以对象的访问也是取决于虚拟机实现而定的。目前主流的访问方式时使用句柄和直接指针两种。

如果使用句柄访问的话,java堆中就会划分出一块内存来作为句柄池,reference类型中存储的就是对象的句柄类型,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。优点是句柄地址稳定,对象被移动后,只需改变句柄中的实例数据指针,而reference本身不需要修改。

如果使用直接指针访问,那么java堆对象的布局就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址。优点是速度更快。

关于学习java虚拟机的知识整理一:jvm内存区域的更多相关文章

  1. Java虚拟机(一):JVM内存结构

    所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问 ...

  2. Java虚拟机(二):JVM内存模型

    所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问 ...

  3. 《深入理解Java虚拟机》之(一、内存区域)

    一.java的体系构成: Java的技术体系主要由支撑java程序运行的虚拟机.提供各种开发领域接口支持的java api.java编程语言及许多第三方java框架(如Spring .Struts等) ...

  4. 深入理解Java虚拟机之读书笔记一 自动内存管理机制

    一.运行时数据区域 1.程序计数器是线程的私有空间,每个线程都有.针对线程执行的是Java代码还是Native代码有两种取值,Java代码时:虚拟机字节码指令的地址:Native代码时:计数值为Und ...

  5. java部分基础知识整理----百度脑图版

    近期发现,通过百度脑图可以很好的归纳总结和整理知识点,本着学习和复习的目的,梳理了一下java部分的知识点,不定期更新,若有不恰之处,请指正,谢谢! 脑图链接如下:java部分基础知识整理----百度 ...

  6. Java虚拟机 - 结构原理与运行时数据区域

    http://liuwangshu.cn/java/jvm/1-runtime-data-area.html 前言 本来计划要写Android内存优化的,觉得有必要在此之前介绍一下Java虚拟机的相关 ...

  7. Java虚拟机------JVM内存区域

    JVM内存区域运行时数据区域分为两种: JVM内存区域 运行时数据区域分为两种: 线程隔离的数据区: 程序计数器 Java虚拟机栈 本地方法栈 所有线程程共享的数据区: Java堆 方法区 JVM 内 ...

  8. 深入理解java:1.3.1 JVM内存区域的划分(运行时数据区)

    学习Java GC机制,可以帮助我们在日常工作中 排查各种内存溢出或泄露问题,解决性能瓶颈,达到更高的并发量,写出更高效的程序. 我们将从4个方面学习Java GC机制, 1,内存是如何分配的: 2, ...

  9. JVM基础知识(1)-JVM内存区域与内存溢出

    JVM基础知识(1)-JVM内存区域与内存溢出 0. 目录 什么是JVM 运行时数据区域 HotSpot虚拟机对象探秘 OutOfMemoryError异常 1. 什么是JVM 1.1. 什么是JVM ...

随机推荐

  1. Java中类的关系

    在java里类的关系大致分为三种, 1.继承(a is b):继承extends,实现implement 2.包含(a has b):组合>聚合>关联.关系亲密度越来越小,一个类在另一个类 ...

  2. vuejs之vue和springboot后端进行通信

    一.新建一个vue项目,建立好后的相关文件 查看一下新建好的vue项目的结构: 当前各个文件中的内容: App.vue:主入口 <template> <div id="ap ...

  3. golang函数 和 条件语句

    /* if : if 语句 由一个布尔表达式后紧跟一个或多个语句组成 is else : if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行 s ...

  4. 《自拍教程5》Python自动化测试学习思路

    前提:熟悉测试业务及流程 任何Python自动化测试的前提,都是必须先熟悉实际测试业务. 任何脱离实际测试业务的自动化都是噱头且无实际意义! 测试的基本流程基本是: 测试需求分析,测试用例设计与评审, ...

  5. 获取页面form表单对象的方式

    w3c并没有提供标准的这种使用方式,所以各浏览器实现会有差异,还是使用标准的w3c标准,getElement的方式. 记录下,老是忘记 使用documen对象的方法 getElementxxx 方式, ...

  6. spark读取文件机制 源码剖析

    Spark数据分区调研 Spark以textFile方式读取文件源码 textFile方法位于 spark-core_2.11/org.apache.spark.api.java/JavaSparkC ...

  7. [Pyhton]连接MSSQL实例并执行SQL语句

    运行环境: 服务器端: MSSQL 2014 Server 2012 R2 程序端: Python 3.7.4 MacOS 10.14.6 CentOS Linux release 7.7.1908 ...

  8. Windows下配置开机自启Tomcat服务

    给单位内部做了一个管理系统,部署项目要求服务器启动管理系统自启..直接给出操作流程. 一.配置环境变量 由于Tomcat启动依赖jdk,因此需要配置jdk与Tomcat两项环境变量,如系统已安装jdk ...

  9. vue中子组件触发父组件的方法

    网上找了几种方法,下面这两种最实用,最明了 方法一:父组件方法返回是字符串或数组时用这种方法 子组件: <template> <button @click="submit& ...

  10. SpringCloud学习之—Eureka集群搭建

    Eureka集群的搭建 上次说过了在SpringCloud应用中使用Eureka注册中心,用来对服务提供者进行服务注册与发现,但同时,它也是一个"微服务",单个应用使用空间有限,因 ...