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

如上图所示,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. Coroutine 练习 1 - Coroutine Exercises 1

    Coroutine 练习 1 - Coroutine Exercises 1 字典中为动词 “to yield” 给出了两个释义:产出和让步.对于 Python 生成器中的 yield 来 说,这两个 ...

  2. 浏览器中的 .Net Core —— Blazor WebAssembly 初体验

    前言 在两年多以前就听闻 Blazor 框架,是 .Net 之父的业余实验性项目,其目的是探索 .Net 与 WebAssembly 的兼容性和应用前景.现在这个项目已经正式成为 Asp.Net Co ...

  3. SELinux 和 iptables 开启关闭

    SELinux 是 2.6 版本的 Linux 内核中提供的强制访问控制(MAC)系统.对于目前可用的 Linux安全模块来说,SELinux 是功能最全面,而且测试最充分的,它是在 20 年的 MA ...

  4. Waymo-自动驾驶长尾问题挑战(2019)

    尽管Waymo已经在开放道路上积累超过10 Million Miles,Waymo的工程师们仍然发现有层出不穷的新自动驾驶场景待解决. 1.自动驾驶长尾场景举例 场景一:一个骑自行车的人手中拿着一个S ...

  5. css实现文字过长显示省略号的方法

    <div class="title">当对象内文本溢出时显示省略标记</div> 这是一个例子,其实我们只需要显示如下长度: css实现网页中文字过长截取. ...

  6. mac系统目录结构

    1 符合unix传统的目录 /bin 传统unix命令的存放目录,如ls,rm,mv等. /sbin 传统unix管理类命令存放目录,如fdisk,ifconfig等等. /usr 第三方程序安装目录 ...

  7. 使用Nginx对.NetCore站点进行反向代理

    前言 之前的博客我已经在Linux上部署好了.NetCore站点且通过Supervisor对站点进行了进程守护,同时也安装好了Nginx.Nginx的用处非常大,还是简单说下,它最大的功能就是方便我们 ...

  8. PWN之Canary学习

    Canary 参考链接:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/mitigation/canary-zh/ 0x1 简介: 用于防止栈溢出被利用的一 ...

  9. 记录 Spine骨骼动画导入unity 步骤[unity3d 4.6.6版本 2d动画]

    1:准备好unity使用Spine所需要的运行库,可到如下地址 https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine ...

  10. 今天带来compass的使用方式

    一.为什么我们要使用compass呢 Experience cleaner markup without presentational classes. It’s chock full of the ...