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

  • 时间:
  • 浏览:0
  • 来源:大发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区,以及一个多多 大小相同的Survivor区(From Survivor,To Survivor)。默认情形下,Java虚拟机采取的是你你这个动态分配的策略(JVM参数-XX:+UsePSAdaptiveSurvivorSizePolicy),根据生成对象的下行速率 ,以及Survivor区的使用情形,动态调整Eden区和Survivor区的比例。也须要通过参数(SurvivorRatio)来调整你你这个比例,SurvivorRatio你你这个参数什么都 新生代中Eden区与Survivor区的容量比值,默认是8,代表Eden:Survivor=8:1。

否是将会三个白多多 对象共用一段内存的事故?

当调用new指令时,会在Eden区划出一块作为存储对象的内存。将会堆空间是进程共享的,或者直接在这上方划空间是须要进行同步的。或者,将有将会再次一个劲出现一个多多 对象共用一段内存的事故。正确处理最好的辦法 什么都 ,Java堆中将会划出多个进程私有的分配缓冲区TLAB(Thread Local Allocation Buffer,对应的虚拟机参数-XX:+UseTLAB,默认开启)。

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

3.最好的辦法 区(Method Area)

最好的辦法 区与堆一样是进程共享的,在虚拟机启动的什么都 创建,最好的辦法 区可视为堆的一个多多 逻辑每段,或者它却三个白多多 别叫兰做Non-Heap(非堆),目的应该是与Java堆区分开来。

最好的辦法 区类事于传统语言编译后的代码存储区域,它存储每个类的价值形式信息,如:

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

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

Java虚拟机规范对最好的辦法 区的限制非常宽松,除了和Java堆一样不须要连续的内存和须要选取 固定大小将会可扩展外,须要选取 不实现垃圾收集。这区域的内存回收目标主什么都 针对常量池的回收和对类型的卸载。

4.进程计数器(Program Counter Register)

Java虚拟机须要支持多条进程一块儿执行,每每根Java虚拟机进程都有我个人的进程计数器。在任意时刻,每根Java虚拟机进程只会执行一个多多 最好的辦法 的代码,你你这个正在被进程执行的最好的辦法 称为该进程的当前最好的辦法 (current methon)。将会你你这个最好的辦法 都有native的,那进程计数器保存的什么都 Java虚拟机正在执行的字节码指令的地址。将会该最好的辦法 是native最好的辦法 ,那进程计数器的值为空(undefined)。进程计数器的容量相当于应当保存一个多多 returnAddress类型的数据将会一个多多 与平台相关的本地指针的值。

进程计数器是一块较小的内存空间,它须要看作是当前进程所执行的字节码的行号指示器。此内存区域是唯一一个多多 在Java虚拟机规范中那末 规定任何OutOfMemoryError情形的区域。

5.虚拟机栈(VM Stack)

每每根Java虚拟机进程都有我个人私有的Java虚拟机栈,它的生命周期与进程相同。虚拟机栈描述的是Java最好的辦法 执行的内存模型:每个最好的辦法 在执行的一块儿都会创建一个多多 栈帧(stack frame)用于存储局部变量表、操作数栈、动态链接、最好的辦法 出口等信息。每一个多多 最好的辦法 从调用直至执行完成的过程,就对应着一个多多 栈帧在虚拟机栈中入栈到出栈的过程。

Java虚拟机栈将会趋于稳定如下异常情形:

  • 将会进程请求分配的栈容量超过Java虚拟机栈允许的最大容量,Java虚拟机将会抛出一个多多 StackOverflowError异常。
  • 将会Java虚拟机栈须要动态扩展,或者在尝试扩展的什么都 无法申请到足够的内存,将会在创建新的进程时那末 足够的内存区创建对应的虚拟机栈,那Java虚拟机将会抛出一个多多 OutOfMemoryError异常

6.本地最好的辦法 栈(Native Method Stack)

本地最好的辦法 栈与虚拟机栈所发挥的作用是非常类事的,它们之间的区别不过是虚拟机栈为虚拟机执行Java最好的辦法 (也什么都 字节码)服务,而本地最好的辦法 栈则为虚拟机使用到的native最好的辦法 服务。

Java虚拟机规范允许本地最好的辦法 栈实现成固定大小将会根据计算来动态扩展和收缩。将会采用固定大小的本地最好的辦法 栈,那末 每一个多多 进程的本地最好的辦法 栈容量须要在创建栈的什么都 独立选定。

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

7.扩展知识点

7.1 栈上分配和逃逸分析

在栈中分配的基本思路是什么都 的:分析局部变量的作用域仅限于最好的辦法 实物,则JVM直接在栈帧内分配对象空间,正确处理在堆中分配。你你这个分析过程称为逃逸分析(都有叫逸出分析),而栈帧内分配对象的最好的辦法 称为栈上分配

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

7.2 栈帧

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

在编译进程代码的什么都 ,栈帧中须要多大的局部变量表,多深的操作数栈都将会删改选取 了,或者写入到最好的辦法 表的Code属性之中。或者一个多多 栈帧须要分配几个内存,不必收到进程运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。

一个多多 进程中的最好的辦法 调用链将会会很长,什么都最好的辦法 都一块儿趋于稳定执行情形。对于执行引擎来说,在活动进程中,非要趋于稳定栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),与你你这个栈帧相关联的最好的辦法 称为当前最好的辦法 (Current Method)。执行引擎运行的所有字节码指令都只针对当前栈帧进行操作。栈帧的概念价值形式如下:

8.运行时数据区脑图