深入理解Java虚拟机阅读心得21/4/22

运行时常量池
*运行时常量池属于方法区的一部分,用来存储编译期间生成的各种字面量和引用,其比较重要的特性就是动态性,你可以在运行期间向里添加数据,在JAVAAPI中用到这个特性比较常见的就是String的intern()方法。*既然是方法区的一部分,自然受方法区管理,当内存不足时会弹出OutOfMemoryError异常。

直接内存
直接内存并不属于虚拟机运行时数据区的一部分,也不是Java虚拟机规范定义的部分,但这部分区域的内存也被频繁的使用,也会导致OutOfMemoryError异常出现。**因为在JDK1.4中新引入了NIO类,加入了一种基于通道和缓冲区的IO方式,它通过本地函数库直接分配堆外内存,然后通过一个存储在堆中的对象作为这块内存的引用进行操作,这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。*而之所以这块区域会产生异常,是因为服务器管理员在配置虚拟机参数时,会经常忽略直接内存,这样就会使得各个内存总区域大于物理内存限制,这个限制有可能是物理上的,也可能是操作系统的限制,从而在其动态扩展是会爆出上述异常。

对象的创建
Java是一门面向对象的语言,在运行过程中会有无数的新对象被创建出来,在程序开发人员看来,新建一个对象就是一个New,那在虚拟机眼中看来,一个对象的创建是什么样的呢,当一个new指令被执行时,虚拟机会首先将这个指令的参数在常量池中搜索能否定义到一个类的符号引用,并且检查这个类是否已被加载解析初始化过,如果没有,那必须先执行对应的类加载过程。在类的加载过程检查通过后,虚拟机就将为该对象分配对应的内存空间,这个过程有两种分配方式,如果内存中有两块规整连续的区域,而在区域中间有一个指针,那么给该对象分配空间的过程就只需要将指针向右移动即可,这种分配方式叫做指针碰撞。而另一种就是在内存空间并不规整的情况下使用,当其不连续时,虚拟机就需要维护一个列表,上面记录了那些区域已被使用以及还有哪些空闲区域,当给新增对象赋予空间时,就在列表中找到一个足够大的区域并维护其中的使用信息,这种方式叫做空闲列表。**选择哪种分配方式由Java堆是否规整决定,而堆内存是否规整则由所采用的垃圾回收工具是否具有压缩整理功能决定。**除了如何配分空间外,还有一个需要考虑的就是对象创建在虚拟机中是非常频繁的行为,在并发情况下,无论是做什么操作都不是线程安全的,比如指针碰撞中的改变指针指向的位置,有可能虚拟机正在给A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针分配内存的情况,这个问题有两种解决方案,一种是对分配内存空间的动作进行同步处理,实际上虚拟机采用CAS配上失败重试的方式来保证更新操作的原子性,另一种则是将内存的分配动作按照不同的线程划分在不同的空间之中,就是每个线程事先就在Java堆中拿下一小块内存,叫做本地线程分配缓冲(TLAB),哪个线程要分配内存,就先在其拥有的这块内存上分配,只有当这一块区域用完时,才需要同步锁定,虚拟机是否使用该技术,可以通过-XX:+/-UseTLAB参数来设定。内存分配完毕后,虚拟机要将对象分配到的内存都初始化为零值(不包括对象头),如果使用TLAB,这个步骤也可以提前到TLAB分配时就进行。这个操作保证了对象的实例字段在代码中可以不用赋值就直接使用,程序能访问到这些字段的数据类型所对应的零值。接下来,虚拟机会对对象进行必要的设置,比如其是哪个类的实例,对象的哈希值等等,这些信息都存放在对象的对象头中,根据虚拟机当前的运行状态不同,对象头会有不同的设置方式。到这里,从虚拟机的角度来看,一个新对象就已经产生了,但从程序的视角来看,对象创建才刚刚开始,方法还没有执行(由字节码中的指令决定),所有的字段都是零,一般来说,执行new指令后会跟着执行方法,把对象按照开发人员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。

  • 1
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值