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

  • 时间:
  • 浏览:13
  • 来源:小和博客 - 专注共享杨小杰博客资源

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

  里面扯了那么多,相信你将会知道“你”就代表着有三个多 系统守护进程,“国家”指的是JVM,“国家”圈的一块“地”所以我堆空间,你娶的“对象”所以我实例对象,“国家”分配地的动作所以我内存分配,而国家征收的动作所以我垃圾回收。

  2)、 本地系统守护进程分配缓冲区:把分配的内存按照不同的系统守护进程划分在不同的空间进行,每个系统守护进程在java堆区预先分配一小块内存,称为本地系统守护进程分配缓冲区(Thread Local Allocation Buffer)。哪个系统守护进程时需分配就从哪个系统守护进程的TLAB上分配,必须在TLAB用完时需分配新的TLAB的刚刚才时需做同步补救(通过上有些中的CAS机制)。

  JVM在堆区划分一块内存作为句柄池,引用类型变量中存储所以我对象的句柄地址。对象句柄包涵盖三个多 地址(如下图):

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

  2、你有些对象类型数据地址。

      

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

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

  2)、 空闲列表

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

      

  将会要找对象的人太少了,所以有分配的操作也很频繁,那么摆在“国家”的问题图片图片就来了:为什么在合理分配?为什么在最大限度的提高空间利用率?为什么在提高分配速率单位?我太少 了的空间为什么在回收?为什么在知道哪几种空间我太少 了?里面所以有问题图片图片都时需结合里面的垃圾回收相关的内容来讨论,这里只讨论分配内存的方式。

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

  具体类的加载、解析、初始化的过程亲们还都都可以 去查找JVM类加载机制相关资料,这里就不展开啦!亲们时需知道的是你有些步保证了在方式区中,处在要创建实例对象的类对象

  在上文亲们提过有些问题图片图片,你的对象是为什么在new出来的?new出来又放满哪里?为什么在引用的? 老规矩,亲们还是通过字节码来了解一下。

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

      

  句柄池的方式会在句柄池中存放类型对象的相关信息,而直接访问的方式会把类型对象的信息放满实例对象的对象头中(亲们知道对象头涵盖“指向对象类型数据的指针”,确实这并都是时需的,亲们常用的HotSpot虚拟机采用的是直接指针的方式,所以有对象头中会涵盖“指向对象类型数据的指针”,将会某类虚拟机采用的是句柄的方式访问对象,那将会就不时需在头部存储你有些指针了)。有些种方式都互有优缺点:

  有三个多 对象时需占用多大的内存?你有些问题图片图片其确实类加载完成后就将会选取啦!JVM还都都可以 通过普通java对象的类元信息选取对象大小。为对象分配内存相当与把一块选取大小的内存从java堆中划分出来。那么问题图片图片来了,那么大的一块堆空间摆在JVM的转过身,JVM该划哪一块空间来分配内存呢?随机找一块空间分配算了?or紧挨着刚刚分配的空间里面进行分配?这里时需说到的是这个分配方式:

  JVM遇到new指令时,先检查指令参数(里面字节码中的#2)是不是 能在常量池中定位到有三个多 类的符号引用(里面最终定位到常量池中的com/test/entity/People):

  1)、将会能定位到,检查你有些符号引用代表的类是不是 已被加载、解析和初始化过;

  2)、将会必须定位到,或那么检查到,就先执行相应的类加载过程;

  1)、 同步补救:JVM采用CAS(Compare and Swap)机制加在失败重试的方式,保证更新操作的原子性。CAS机制是这个轻量级锁机制,后续在聊多系统守护进程的刚刚再讲!

  1)、 指针碰撞

  亲们看看对应的字节码

  astore依然时需弹出栈顶值,所以我存储到编号为1的变量中供后续使用。至此有三个多 全版的对象将会创建且返回对象内存引用给本地变量存储了。

  invokespecial指令调用对象实例方式<init>,通过符号引用#3定位到的是People对象的实例方式<init>。这刚刚操作数栈栈顶值(指向对象实例的内存reference)会被弹出(将会<init>方式有参数,参数也会出栈)。执行<init>方式会在java虚拟机栈中创建<init>方式的栈帧(相关栈和栈帧的介绍看上一篇文章),所以我把出栈的数据放满栈帧的局部变量表中。变量表中指向对象实例的内存reference所以我亲们老要 用到的this,表示对该对象实例进行操作!执行完该指令后,有三个多 全版的对象就创建完成啦!

  咦!一看字节码才知道,亲们的一行new的代码,对应的字节码所以我要做那么多操作!亲们逐一来分析一下。

  所以我的代码亲们有些所以我会陌生,亲们都知道使用new关键字还都都可以 创建有三个多 对象,对应的字节码如下

  

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

  亲们里面将会把对象创建的问题图片图片补救了,并肩亲们也都知道,引用类型的变量存储的是**对象的引用**!那你有些引用类型数据为什么在定位到堆中的对象呢?目前主流的对象访问方式有这个:

  内存分配刚刚,就时需初始化实例对象了,虚拟机时需将分配到的内存空间中的数据类型都初始化为零值(不包括对象头,将会是使用TLAB,初始化0值的操作提前至分配TLAB时)。接下来虚拟机要对对象进行必要的设置,类似于你有些对象是哪个类的实例、怎样才能都还都都可以找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息,哪几种信息都存放满对象的对象头中。做完以上刚刚,从虚拟机视角来看,有三个多 新的对象将会产生了!

  dup命令没猜错话语是duplicate的简写。在讨论dup命令前,亲们先看有三个多 简单的例子

  将会88你有些值在第一条话语中时需重复赋给有三个多 变量,所以有使用dup指令对栈顶的值进行了克隆,且压入栈顶。亲们在new对象的刚刚,new指令里面完会 紧跟dup指令!所以我是invokespecial和astore指令,相信聪明的你应该想到invokespecial和astore指令完会 时需从栈顶弹出值来执行!在执行完dup指令后,操作数栈栈顶都是有三个多 指向该对象实例内存的reference数据,将会<init>方式有参数,还时需把参数加载到操作栈。

  亲们能看多,导致 有些种方式的差异主要取决于java堆是不是 规整,而java堆是不是 规整又是由jvm采用的垃圾采集器是不是 涵盖压缩功能决定的。使用Serial、ParNew等带Compact过程的采集器时,JVM采用指针碰撞方式分配内存。而使用CMS你有些基于标记-清除(Mark-Sweep)算法的采集器时,采用空闲列表方式。(下篇文章会具体介绍不同的垃圾采集器)

  不管是指针碰撞还是空闲列表,完会 处在同有三个多 问题图片图片,那所以我在多系统守护进程的场景下的系统守护进程安全问题图片图片。多个系统守护进程并肩在new的刚刚把对象分配到同一块内存了咱办,不得干起来么!于是jvm采用了这个方案来补救:

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

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

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

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

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