【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.运行时数据区脑图