你必须了解的java内存管理机制(二)

  • 时间:
  • 浏览:11
  • 来源:我爱搬资源网 - 专注共享唐朝博客活动

  2)、可还还上能定位到,或没人检查到,就先执行相应的类加载过程;

  JVM遇到new指令时,先检查指令参数(底下字节码中的#2)是与否能在常量池中定位到另3个 类的符号引用(底下最终定位到常量池中的com/test/entity/People):

  1)、可还还上能定位到,检查这人 符号引用代表的类是与否已被加载、解析和初始化过;

  引用类型变量中存储可是 在堆中分配的对象实例数据的地址。

      

  句柄池的方法会在句柄池中存放类型对象的相关信息,而直接访问的方法会把类型对象的信息贴到 实例对象的对象头中(我们都歌词 我们都歌词 我们都歌词 知道对象头包含“指向对象类型数据的指针”,实在 这并也有前要的,我们都歌词 我们都歌词 我们都歌词 常用的HotSpot虚拟机采用的是直接指针的方法,什么都有对象头中会包含“指向对象类型数据的指针”,可能某类虚拟机采用的是句柄的方法访问对象,那可能就不前要在头部存储这人 指针了)。这两种生活方法都互有优缺点:

  1)、 指针碰撞

  JVM完成对象内存的分配及对象初始化可是,会返回对象的地址,可是 压入操作数的栈顶,供后续操作!

  内存分配可是,就前要初始化实例对象了,虚拟机前要将分配到的内存空间中的数据类型都初始化为零值(不包括对象头,可能是使用TLAB,初始化0值的操作提前至分配TLAB时)。接下来虚拟机要对对象进行必要的设置,类事于这人 对象是哪个类的实例、如可都还还上能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息,哪些地方地方信息都存贴到 对象的对象头中。做完以上可是,从虚拟机视角来看,另3个 新的对象可能产生了!

  2)、 空闲列表

  可能Java堆也有规整的:用过的和空闲的内存相互交错。前要维护另3个 列表,记录哪些地方内存可用。分配内存时查表找到另3个 足够大的内存,并更新列表,这人 分配方法称为"空闲列表"(Free List)。类事于下图,好好的一块内存被绿得乱七八糟,用底下指针碰撞的方法是碰不动了!什么都有就用另3个 小本本记着哪里有多大的空闲空间还还上能绿!当然下图的地址编号是虚拟的,空闲列表的样子也是我意淫出来的,表达的意思你懂就行! 

      

  在上一篇文章中,我们都歌词 我们都歌词 我们都歌词 花了较大的篇幅去介绍了JVM的运行时数据区,可是 重点介绍了栈区的行态及作用,相关内容请猛戳!在本文中,我们都歌词 我们都歌词 我们都歌词 将主要介绍对象的创建过程及在堆中的分配方法。

  invokespecial指令调用对象实例方法<init>,通过符号引用#3定位到的是People对象的实例方法<init>。这可是操作数栈栈顶值(指向对象实例的内存reference)会被弹出(可能<init>方法有参数,参数也会出栈)。执行<init>方法会在java虚拟机栈中创建<init>方法的栈帧(相关栈和栈帧的介绍看上一篇文章),可是 把出栈的数据贴到 栈帧的局部变量表中。变量表中指向对象实例的内存reference可是 我们都歌词 我们都歌词 我们都歌词 老是 用到的this,表示对该对象实例进行操作!执行完该指令后,另3个 详细的对象就创建完成啦!

  咱们到了适婚年龄,也就该找个对象了吧!你看上了另3个 姑娘,长得楚楚动人,就跑去跟他妈说:“我我应该 要要另3个 对象,把你女儿嫁给我吧!”。她妈妈倒是十分爽快:“好啊,我女儿总得有个地方住吧,小伙子你有房吗?”。这可是场面一度十分尴尬,心里嘀咕着“可是 国家能分配房子就好了!”。这在当前社会显然不现实,毕竟咱们还没进入共产主义社会!然而在JVM王国里,对象住的“房子”却是“国家”统一分配的。国家集中圈了一大块“地”,谁家要娶“媳妇”,就给他家分配一块“地”,“媳妇”胖点呢,地就大一点,“媳妇”瘦一点呢,“地”就小一点。在这里,你另3个 人还还上能并肩拥有多个对象,在这里,多被委托人还还上能拥有同另3个 对象。什么都有这里的老百姓安居乐业、这里一片祥和……当然,可能这块“地”大小有限,而你又并肩拥有什么都有对象,还有被委托人也要娶对象,什么都有哪些地方地方不让了的对象的“地”国家就会进行统一征收(当然这里不让给补贴,毕竟是免费分配的~)以继续分给被委托人用。

  底下扯了没人多,相信你可能知道“你”就代表着另3个 守护程序,“国家”指的是JVM,“国家”圈的一块“地”可是 堆空间,你娶的“对象”可是 实例对象,“国家”分配地的动作可是 内存分配,而国家征收的动作可是 垃圾回收。

  JVM在堆区划分一块内存作为句柄池,引用类型变量中存储可是 对象的句柄地址。对象句柄包含另3个 地址(如下图):

  1、在堆中分配的对象实例数据的地址。

  2、这人 对象类型数据地址。

      

  原先的代码我们都歌词 我们都歌词 我们都歌词 一点可是 会陌生,我们都歌词 我们都歌词 我们都歌词 都知道使用new关键字还还上能创建另3个 对象,对应的字节码如下

  

  astore依然前要弹出栈顶值,可是 存储到编号为1的变量中供后续使用。至此另3个 详细的对象可能创建且返回对象内存引用给本地变量存储了。

  我们都歌词 我们都歌词 我们都歌词 能看到,意味着着 这两种生活方法的差异主要取决于java堆是与否规整,而java堆是与否规整又是由jvm采用的垃圾派发器是与否包含压缩功能决定的。使用Serial、ParNew等带Compact过程的派发器时,JVM采用指针碰撞方法分配内存。而使用CMS这人 基于标记-清除(Mark-Sweep)算法的派发器时,采用空闲列表方法。(下篇文章会具体介绍不同的垃圾派发器)

  不管是指针碰撞还是空闲列表,一定会指在同另3个 什么的什么的问题 ,那可是 在多守护程序的场景下的守护程序安全什么的什么的问题 。多个守护程序并肩在new的可是把对象分配到同一块内存了咋整,不得干起来么!于是jvm采用了两种生活方案来处里:

  可能88这人 值在根小语句中前要重复赋给另3个 变量,什么都有使用dup指令对栈顶的值进行了克隆,且压入栈顶。我们都歌词 我们都歌词 我们都歌词 在new对象的可是,new指令底下一定会紧跟dup指令!可是 是invokespecial和astore指令,相信聪明的你应该想到invokespecial和astore指令一定会前要从栈顶弹出值来执行!在执行完dup指令后,操作数栈栈顶也有另3个 指向该对象实例内存的reference数据,可能<init>方法有参数,还前要把参数加载到操作栈。

  具体类的加载、解析、初始化的过程我们都歌词 我们都歌词 我们都歌词 还还上能去查找JVM类加载机制相关资料,这里就不展开啦!我们都歌词 我们都歌词 我们都歌词 前要知道的是这人 步保证了在方法区中,指在要创建实例对象的类对象

  可能要找对象的人没人来越多了,什么都有分配的操作也很频繁,没人摆在“国家”的什么的什么的问题 就来了:为什么合理分配?为什么最大限度的提高空间利用率?为什么提高分配速度?不让了的空间为什么回收?为什么知道哪些地方空间不让了?底下什么都有什么的什么的问题 都前要结合底下的垃圾回收相关的内容来讨论,这里只讨论分配内存的方法。

  在上文我们都歌词 我们都歌词 我们都歌词 提过一点什么的什么的问题 ,你的对象是为什么new出来的?new出来又贴到 哪里?为什么引用的? 老规矩,我们都歌词 我们都歌词 我们都歌词 还是通过字节码来了解一下。

  dup命令没猜错语句是duplicate的简写。在讨论dup命令前,我们都歌词 我们都歌词 我们都歌词 先看另3个 简单的例子

  2)、 直接指针对象相对句柄方法访问节省了一次指针定位的时间开销,性能更好。可能对象访问非常频繁,提升会更明显!可是 在对象移动时,栈上的变量的引用也前要变化。

  我们都歌词 我们都歌词 我们都歌词 底下可能把对象创建的什么的什么的问题 处里了,并肩我们都歌词 我们都歌词 我们都歌词 也都知道,引用类型的变量存储的是**对象的引用**!那这人 引用类型数据为什么定位到堆中的对象呢?目前主流的对象访问方法有两种生活:

  1)、 句柄方法访问对象时,多一次指针定位的时间开销。可是 对象移动时(垃圾回收时常见的动作),栈上的变量的引用不前要修改,只需改变句柄中实例数据指针。

  咦!一看字节码才知道,我们都歌词 我们都歌词 我们都歌词 的一行new的代码,对应的字节码原先要做没人多操作!我们都歌词 我们都歌词 我们都歌词 逐一来分析一下。

  另3个 对象前要占用多大的内存?这人 什么的什么的问题 其实在 类加载完成后就可能选则 啦!JVM还还上能通过普通java对象的类元信息选则 对象大小。为对象分配内存相当与把一块选则 大小的内存从java堆中划分出来。没人什么的什么的问题 来了,没人大的一块堆空间摆在JVM的身旁,JVM该划哪一块空间来分配内存呢?随机找一块空间分配算了?or紧挨着可是分配的空间底下进行分配?这里前要说到的是两种生活分配方法:

  我们都歌词 我们都歌词 我们都歌词 看看对应的字节码

  1)、 同步处里:JVM采用CAS(Compare and Swap)机制加进失败重试的方法,保证更新操作的原子性。CAS机制是两种生活轻量级锁机制,后续在聊多守护程序的可是再讲!

  相关链接(注:文章讲解JVM以Hotspot虚拟机为例,jdk版本为1.8,被委托人技术博客www.17coding.info)

  1、 你前要了解的java内存管理机制-运行时数据区

  2、 你前要了解的java内存管理机制-内存分配

  3、 你前要了解的java内存管理机制-垃圾标记

  4、 你前要了解的java内存管理机制-垃圾回收

  2)、 本地守护程序分配缓冲区:把分配的内存按照不同的守护程序划分在不同的空间进行,每个守护程序在java堆区预先分配一小块内存,称为本地守护程序分配缓冲区(Thread Local Allocation Buffer)。哪个守护程序前要分配就从哪个守护程序的TLAB上分配,没人在TLAB用完前要分配新的TLAB的可是才前要做同步处里(通过上一点中的CAS机制)。