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

  • 时间:
  • 浏览:0

这里大家先说句题外话,相信大家在面试中老是被问到介绍Java内存模型,我在面试别人时也会老是问什儿 问题。我你要,往往总要令我比较尴尬,我还话音未落,面试者就会“背诵”一段(Java虚拟机时有堆、土方法去、虚拟机栈,吧啦吧啦。。。),估计心里还一脸自豪的想幸好哥提前在网上搜过,早有准备。每每什儿 以前,我都不 忍心打断,机会“背诵”的真的太顺畅了!

这也怪不得面试者,首先Java虚拟机方面的知识,对中高级系统tcp连接猿来说,工作中正面接触Java虚拟机的东西没有来越多。其次,什儿 其次咱得好好唠唠,网上搜个Java内存模型,度娘推的第一页大都不 介绍Java运行时数据区的,起到了一定的误导作用,大写的尴尬。

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

1.运行时数据区介绍

系统tcp连接运行所需的内存空间,一点是不到在编译期就能挑选,得要在运行期根据实际运行情况报告动态地在系统中创建。Java虚拟机在执行Java系统tcp连接的过程中会把它所管理的内存划分为若干个不同的数据区域。哪些区域都不 人个所有的用途,以及创建和销毁的时间,有的区域随着虚拟机系统tcp连接的启动而处在,一点区域则依赖用户系统tcp连接的启动和开始 而建立和销毁。

如图所示,堆和土方法区是所有系统tcp连接共享的公共区域,堆和土方法区所占的内存空间是由JVM负责管理的,在该区域内的内存分配是由HotSpot的内存管理模块维护的,而内存的释放工作则由垃圾挂接器自动完成。虚拟机栈、本地土方法栈、系统tcp连接计数器是系统tcp连接的私有区域,每个系统tcp连接都关联着唯一的栈和系统tcp连接计数器,并仅能使用属于另一方的那份栈空间和系统tcp连接计算器来执行系统tcp连接。

2.堆(Heap)

对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。堆是可供各个系统tcp连接共享的运行时内存区域,在虚拟机启动的以前就被创建。此内存区域的唯一目的可是我存放对象实例,几乎所有的对象实例都不 这里分配内存。什儿 点在Java虚拟机规范中的描述可是我:所有的对象实例以及数组对象都不 在堆上分配。我你要随着JIT编译器的发展与逃逸分析技术逐渐心智性心智成熟是什么是什么的句子的句子 ,栈上分配、标量替换优化技术机会意味着 一点微妙的变化处在,所有的对象都分配在堆上也渐渐变得都不 没有“绝对”了。

Java堆的容量还可不能不能是固定的,也还可不能不能随着系统tcp连接执行的需求动态扩展,并在不须要没有来越多空间时自动收缩。Java堆还可不能不能处在物理上不连续的内存空间中,假使 逻辑上是连续的即可。机会在堆中没有内存完成实例分配,我你要堆也无法再扩展时,机会抛出OutOfMemoryError异常。

Java堆是垃圾挂接器管理的主要区域,我你要统统 以前也被称做“GC堆”(Garbage Collected Heap)。从内存回收的宽度来看,机会现在挂接器基本都采用分代挂接算法,Java虚拟机将堆划分为新生代和老年代。其中,新生代又被分为Eden区,以及另另有俩个多大小相同的Survivor区(From Survivor,To Survivor)。默认情况报告下,Java虚拟机采取的是什儿 动态分配的策略(JVM参数-XX:+UsePSAdaptiveSurvivorSizePolicy),根据生成对象的下行速度 ,以及Survivor区的使用情况报告,动态调整Eden区和Survivor区的比例。也还可不能不能通过参数(SurvivorRatio)来调整什儿 比例,SurvivorRatio什儿 参数可是我新生代中Eden区与Survivor区的容量比值,默认是8,代表Eden:Survivor=8:1。

是有无机会有另另有俩个多对象共用一段内存的事故?

当调用new指令时,会在Eden区划出一块作为存储对象的内存。机会堆空间是系统tcp连接共享的,我你要直接在这上面划空间是须要进行同步的。我你要,将有机会再次出現另另有俩个多对象共用一段内存的事故。防止土方法可是我,Java堆中机会划出多个系统tcp连接私有的分配缓冲区TLAB(Thread Local Allocation Buffer,对应的虚拟机参数-XX:+UseTLAB,默认开启)。

具体来说,每个系统tcp连接还可不能不能向Java虚拟机申请一段连续内存,比如2048字节,作为系统tcp连接私有的TLAB。什儿 操作须要加锁,系统tcp连接须要维护另另有俩个多指针(实际上机会更多,但重要也就另另有俩个多),另另有俩个多指向TLAB中空余内存的起始位置,另另有俩个多则指向TLAB末尾。接下来的new指令,便还可不能不能直接通过指针加法(bump the pointer),都不 人叫做指针碰撞来实现,即把指向空余内存位置的指针加带所请求的字节数。机会加法后空余内存指针的值仍小于或等于指向末尾的指针,则代表分配成功。我你要,TLAB机会没有足够的空间来满足本次新建操作。什儿 以前,便须要当前系统tcp连接重新申请新的TLAB。

3.土方法区(Method Area)

土方法区与堆一样是系统tcp连接共享的,在虚拟机启动的以前创建,土方法区可视为堆的另另有俩个多逻辑部分,我你要它却有另另有俩个多别叫安做Non-Heap(非堆),目的应该是与Java堆区分开来。

土方法区类似于于传统语言编译后的代码存储区域,它存储每个类的型态信息,如:

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

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

Java虚拟机规范对土方法区的限制非常宽松,除了和Java堆一样不须要连续的内存和还可不能不能挑选固定大小机会可扩展外,还还可不能不能挑选不实现垃圾挂接。这区域的内存回收目标主可是我针对常量池的回收和对类型的卸载。

4.系统tcp连接计数器(Program Counter Register)

Java虚拟机还可不能不能支持多条系统tcp连接一并执行,三根小Java虚拟机系统tcp连接都不 另一方的系统tcp连接计数器。在任意时刻,三根Java虚拟机系统tcp连接只会执行另另有俩个多土方法的代码,什儿 正在被系统tcp连接执行的土方法称为该系统tcp连接的当前土方法(current methon)。机会什儿 土方法都不 native的,那系统tcp连接计数器保存的可是我Java虚拟机正在执行的字节码指令的地址。机会该土方法是native土方法,那系统tcp连接计数器的值为空(undefined)。系统tcp连接计数器的容量合适 应当保存另另有俩个多returnAddress类型的数据机会另另有俩个多与平台相关的本地指针的值。

系统tcp连接计数器是一块较小的内存空间,它还可不能不能看作是当前系统tcp连接所执行的字节码的行号指示器。此内存区域是唯一另另有俩个多在Java虚拟机规范中没有规定任何OutOfMemoryError情况报告的区域。

5.虚拟机栈(VM Stack)

三根小Java虚拟机系统tcp连接都不 另一方私有的Java虚拟机栈,它的生命周期与系统tcp连接相同。虚拟机栈描述的是Java土方法执行的内存模型:每个土方法在执行的一并总要创建另另有俩个多栈帧(stack frame)用于存储局部变量表、操作数栈、动态链接、土方法出口等信息。每另另有俩个多土方法从调用直至执行完成的过程,就对应着另另有俩个多栈帧在虚拟机栈中入栈到出栈的过程。

Java虚拟机栈机会处在如下异常情况报告:

  • 机会系统tcp连接请求分配的栈容量超过Java虚拟机栈允许的最大容量,Java虚拟机机会抛出另另有俩个多StackOverflowError异常。
  • 机会Java虚拟机栈还可不能不能动态扩展,我你要在尝试扩展的以前无法申请到足够的内存,机会在创建新的系统tcp连接时没有足够的内存区创建对应的虚拟机栈,那Java虚拟机机会抛出另另有俩个多OutOfMemoryError异常

6.本地土方法栈(Native Method Stack)

本地土方法栈与虚拟机栈所发挥的作用是非常类似于的,它们之间的区别不过是虚拟机栈为虚拟机执行Java土方法(也可是我字节码)服务,而本地土方法栈则为虚拟机使用到的native土方法服务。

Java虚拟机规范允许本地土方法栈实现成固定大小机会根据计算来动态扩展和收缩。机会采用固定大小的本地土方法栈,没有每另另有俩个多系统tcp连接的本地土方法栈容量还可不能不能在创建栈的以前独立选定。

与虚拟机栈一样,本地土方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

7.扩展知识点

7.1 栈上分配和逃逸分析

在栈中分配的基本思路是原来的:分析局部变量的作用域仅限于土方法外部,则JVM直接在栈帧内分配对象空间,防止在堆中分配。什儿 分析过程称为逃逸分析(都不 叫逸出分析),而栈帧内分配对象的土方法称为栈上分配

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

7.2 栈帧

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

在编译系统tcp连接代码的以前,栈帧中须要多大的局部变量表,多深的操作数栈都机会全部挑选了,我你要写入到土方法表的Code属性之中。我你要另另有俩个多栈帧须要分配几条内存,不不收到系统tcp连接运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。

另另有俩个多系统tcp连接中的土方法调用链机会会很长,统统 土方法都一并处在执行情况报告。对于执行引擎来说,在活动系统tcp连接中,不到处在栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),与什儿 栈帧相关联的土方法称为当前土方法(Current Method)。执行引擎运行的所有字节码指令都只针对当前栈帧进行操作。栈帧的概念型态如下:

8.运行时数据区脑图