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

  • 时间:
  • 浏览:3
  • 来源:大发pk10_pk10规则_大发pk10规则

这里愿意们愿意们先说句题外话,相信愿意们愿意们在面试中总爱被问到介绍Java内存模型,我在面试别人时也会总爱问这名问題。而且 ,往往完全都是令我比较尴尬,我还话音未落,面试者就会“背诵”一段(Java虚拟机时有堆、最好的妙招去、虚拟机栈,吧啦吧啦。。。),估计心里还一脸自豪的想幸好哥提前在网上搜过,早有准备。每每这名事先,我完全都是忍心打断,肯能“背诵”的真的太顺畅了!

这也怪不得面试者,首先Java虚拟机方面的知识,对中高级任务管理器猿来说,工作中正面接触Java虚拟机的东西太少。其次,这名其次咱得好好唠唠,网上搜个Java内存模型,度娘推的第一页大完全都是介绍Java运行时数据区的,起到了一定的误导作用,大写的尴尬。

本篇将给各位小伙伴先完全介绍Java运行时数据区的组成,Java内存模型也是虚拟机上面的重点,上面会单独抽出一篇来进行介绍。

1.运行时数据区介绍

任务管理器运行所需的内存空间,而且 是不很久 在编译期就能选折 ,得要在运行期根据实际运行状况动态地在系统中创建。Java虚拟机在执行Java任务管理器的过程中会把它所管理的内存划分为若干个不同的数据区域。哪此区域完全都是各人的用途,以及创建和销毁的时间,有的区域随着虚拟机任务管理器的启动而居于,而且 区域则依赖用户任务管理器的启动和开始而建立和销毁。

如图所示,堆和最好的妙招区是所有任务管理器共享的公共区域,堆和最好的妙招区所占的内存空间是由JVM负责管理的,在该区域内的内存分配是由HotSpot的内存管理模块维护的,而内存的释放工作则由垃圾收集器自动完成。虚拟机栈、本地最好的妙招栈、任务管理器计数器是任务管理器的私有区域,每个任务管理器都关联着唯一的栈和任务管理器计数器,并仅能使用属于当时人的那份栈空间和任务管理器计算器来执行任务管理器。

2.堆(Heap)

对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。堆是可供各个任务管理器共享的运行时内存区域,在虚拟机启动的事先就被创建。此内存区域的唯一目的本来存放对象实例,几乎所有的对象实例完全都是这里分配内存。这名点在Java虚拟机规范中的描述本来:所有的对象实例以及数组对象完全都是在堆上分配。而且 随着JIT编译器的发展与逃逸分析技术逐渐心智心智性性成熟 是什么是什么期的句子的句子期期是什么图片 图片 ,栈上分配、标量替换优化技术肯能愿因而且 微妙的变化居于,所有的对象都分配在堆上也渐渐变得完全都是没法了“绝对”了。

Java堆的容量都很久 是固定的,也都很久 随着任务管理器执行的需求动态扩展,并在不很久 太少空间时自动收缩。Java堆都很久 居于物理上不连续的内存空间中,倘若逻辑上是连续的即可。肯能在堆中没法了内存完成实例分配,而且 堆也无法再扩展时,肯能抛出OutOfMemoryError异常。

Java堆是垃圾收集器管理的主要区域,而且 太少事先也被称做“GC堆”(Garbage Collected Heap)。从内存回收的角度来看,肯能现在收集器基本都采用分代收集算法,Java虚拟机将堆划分为新生代和老年代。其中,新生代又被分为Eden区,以及有4个大小相同的Survivor区(From Survivor,To Survivor)。默认状况下,Java虚拟机采取的是并否有动态分配的策略(JVM参数-XX:+UsePSAdaptiveSurvivorSizePolicy),根据生成对象的速率单位单位,以及Survivor区的使用状况,动态调整Eden区和Survivor区的比例。也都很久 通过参数(SurvivorRatio)来调整这名比例,SurvivorRatio这名参数本来新生代中Eden区与Survivor区的容量比值,默认是8,代表Eden:Survivor=8:1。

否有有肯能有有4个对象共用一段内存的事故?

当调用new指令时,会在Eden区划出一块作为存储对象的内存。肯能堆空间是任务管理器共享的,而且 直接在这上面划空间是很久 进行同步的。而且 ,将有肯能出現有4个对象共用一段内存的事故。避免最好的妙招本来,Java堆中肯能划出多个任务管理器私有的分配缓冲区TLAB(Thread Local Allocation Buffer,对应的虚拟机参数-XX:+UseTLAB,默认开启)。

具体来说,每个任务管理器都很久 向Java虚拟机申请一段连续内存,比如2048字节,作为任务管理器私有的TLAB。这名操作很久 加锁,任务管理器很久 维护有4个指针(实际上肯能更多,但重要也完全都是4个),有4个指向TLAB中空余内存的起始位置,有4个则指向TLAB末尾。接下来的new指令,便都很久 直接通过指针加法(bump the pointer),完全都是人叫做指针碰撞来实现,即把指向空余内存位置的指针上加所请求的字节数。肯能加法后空余内存指针的值仍小于或等于指向末尾的指针,则代表分配成功。而且 ,TLAB肯能没法了足够的空间来满足本次新建操作。这名事先,便很久 当前任务管理器重新申请新的TLAB。

3.最好的妙招区(Method Area)

最好的妙招区与堆一样是任务管理器共享的,在虚拟机启动的事先创建,最好的妙招区可视为堆的有4个逻辑每种,而且 它却有有4个别叫金做Non-Heap(非堆),目的应该是与Java堆区分开来。

最好的妙招区相似于传统语言编译后的代码存储区域,它存储每个类的特征信息,如:

  • 常量池
  • 最好的妙招数据
  • 最好的妙招和构造函数的字节码
  • 类、实例、接口初始化时用到的特殊最好的妙招

备注:《深入理解Java虚拟机》里将最好的妙招区归纳为用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

Java虚拟机规范对最好的妙招区的限制非常宽松,除了和Java堆一样不很久 连续的内存和都很久 选折 固定大小肯能可扩展外,还都很久 选折 不实现垃圾收集。这区域的内存回收目标主本来针对常量池的回收和对类型的卸载。

4.任务管理器计数器(Program Counter Register)

Java虚拟机都很久 支持多条任务管理器同時 执行,每每根绳子 Java虚拟机任务管理器完全都是当时人的任务管理器计数器。在任意时刻,每根绳子 Java虚拟机任务管理器只会执行有4个最好的妙招的代码,这名正在被任务管理器执行的最好的妙招称为该任务管理器的当前最好的妙招(current methon)。肯能这名最好的妙招完全都是native的,那任务管理器计数器保存的本来Java虚拟机正在执行的字节码指令的地址。肯能该最好的妙招是native最好的妙招,那任务管理器计数器的值为空(undefined)。任务管理器计数器的容量大概应当保存有4个returnAddress类型的数据肯能有4个与平台相关的本地指针的值。

任务管理器计数器是一块较小的内存空间,它都很久 看作是当前任务管理器所执行的字节码的行号指示器。此内存区域是唯一有4个在Java虚拟机规范中没法了规定任何OutOfMemoryError状况的区域。

5.虚拟机栈(VM Stack)

每每根绳子 Java虚拟机任务管理器完全都是当时人私有的Java虚拟机栈,它的生命周期与任务管理器相同。虚拟机栈描述的是Java最好的妙招执行的内存模型:每个最好的妙招在执行的同時 完全都是创建有4个栈帧(stack frame)用于存储局部变量表、操作数栈、动态链接、最好的妙招出口等信息。每有4个最好的妙招从调用直至执行完成的过程,就对应着有4个栈帧在虚拟机栈中入栈到出栈的过程。

Java虚拟机栈肯能居于如下异常状况:

  • 肯能任务管理器请求分配的栈容量超过Java虚拟机栈允许的最大容量,Java虚拟机肯能抛出有4个StackOverflowError异常。
  • 肯能Java虚拟机栈都很久 动态扩展,而且 在尝试扩展的事先无法申请到足够的内存,肯能在创建新的任务管理器时没法了足够的内存区创建对应的虚拟机栈,那Java虚拟机肯能抛出有4个OutOfMemoryError异常

6.本地最好的妙招栈(Native Method Stack)

本地最好的妙招栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java最好的妙招(也本来字节码)服务,而本地最好的妙招栈则为虚拟机使用到的native最好的妙招服务。

Java虚拟机规范允许本地最好的妙招栈实现成固定大小肯能根据计算来动态扩展和收缩。肯能采用固定大小的本地最好的妙招栈,没法了每有4个任务管理器的本地最好的妙招栈容量都很久 在创建栈的事先独立选定。

与虚拟机栈一样,本地最好的妙招栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

7.扩展知识点

7.1 栈上分配和逃逸分析

在栈中分配的基本思路是原本的:分析局部变量的作用域仅限于最好的妙招内内外部,则JVM直接在栈帧内分配对象空间,避免在堆中分配。这名分析过程称为逃逸分析(完全都是叫逸出分析),而栈帧内分配对象的最好的妙招称为栈上分配

原本做的目的是减少新生代的收集次数,间接提高JVM性能。虚拟机是允许堆逃逸分析开关进行配置的,从Sun Java 6u23事先,HotSpot默认开启逃逸分析。

7.2 栈帧

栈帧是用于支持虚拟机进行最好的妙招调用和最好的妙招执行的数据特征,它是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了最好的妙招的局部变量表、操作数栈、动态连接和最好的妙招返回地址等信息每有4个最好的妙招从调用开始至执行完成的过程,都对应着有4个栈帧在虚拟机栈上面从入栈到出栈的过程。

在编译任务管理器代码的事先,栈帧中很久 多大的局部变量表,多深的操作数栈都肯能完全选折 了,而且 写入到最好的妙招表的Code属性之中。而且 有4个栈帧很久 分配哪几条内存,太少收到任务管理器运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。

有4个任务管理器中的最好的妙招调用链肯能会很长,太少最好的妙招都同時 居于执行状况。对于执行引擎来说,在活动任务管理器中,不很久 居于栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),与这名栈帧相关联的最好的妙招称为当前最好的妙招(Current Method)。执行引擎运行的所有字节码指令都只针对当前栈帧进行操作。栈帧的概念特征如下:

8.运行时数据区脑图