《深入理解Java虚拟机》读书笔记——内存区域、OOM、对象(创建、存储和定位)、String.intern()

1、内存区域和OOM

    (1)程序计数器:较小的空间,可以看作当前线程所执行的字节码的行号指示器(即字节码指令的地址),每条线程都需要一个独立的程序计数器,用于切换线程后能恢复到正确的执行位置,是唯一一个没有规定OOM情况的区域。如果执行的是native方法,计数器为空(native方法体不是由java字节码构成的);

    (2)Java虚拟机栈:线程私有,生命周期与线程相同。每个方法执行时创建栈帧,存储局部变量表、操作数栈、动态链接、方法出口等信息。会StackOverflow(本地变量太大或者递归太深)和OutOfMemory(通常是由于线程数量过多,可以通过减少最大堆容量或者减少栈容量来换取更多的线程);

    (3)本地方法栈:与虚拟机栈类似,只不过为native方法服务;

    (4)Java堆:所有线程共享,存放对象实例(Class对象也在堆中,而不是在方法区,1.6在方法区,1.7以后在堆中),细分为新生代(Eden,From Survivor,To Survivor)和老年代,可以用-Xms、-Xmx分别指定最小值和最大值。没有内存完成实例分配时会抛出OutOfMemoryError,堆OOM时,要先分清楚是内存泄漏还是内存溢出,如果是内存泄漏,要分析泄漏对象是怎么与GC ROOTS相关联,导致垃圾收集器无法回收;

    (5)方法区(永久代):各个线程共享,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。对方法区的垃圾收集效率低,可以设置是否对方法区进行回收。类只有在满足如下三个条件时才能被回收:【1】该类所有的实例已经被回收【2】加载该类的ClassLoader被回收【3】该类的Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。在大量使用反射、动态代理、CGLib等ByteCode框架、动态生成JSP以及OSGi这类频繁自定义ClassLoader的场景都需要虚拟机具备类卸载的功能,否则会OOM

    (6)运行时常量池:方法区的一部分,存放编译期生成的字面量(final变量)和符号引用,符号引用包括类和接口的全限定名、字段的名称和描述符(数据类型)、方法的名称和描述符(参数列表和返回值)。受到方法区大小的限制,会OOM;

    (7)直接内存:例如NIO利用native函数库分配堆外内存,受到本机总内存的限制,会OOM;

      1.8以后永久代和常量池移动到了元空间中,使用直接内存。

 

2、对象

    (1)对象的创建:根据new的参数定位一个符号引用,如果类没有被加载过,先执行类加载过程,对象所需的空间在类加载后确定;在堆上分配内存,为了保证并发安全用自旋CAS保证内存分配的原子性;将分配到的内存空间都初始化为零值(不包括对象头);设置对象头(类型、哈希、GC分代年龄等);执行<init>,按程序员的意愿进行初始化。

    (2)对象的存储:对象在内存中的存储可以分为对象头(Mark Word和类型指针)、实例数据和对齐填充三部分。

    对象头分为两部分,第一部分是“Mark Word”,存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,在32位和64位虚拟机中分别为32bit和64bit,如下图,根据锁标志位的不同存储不同的信息

    第二部分是类型指针,即对象指向它的类元数据的指针,来确定对象是哪个类的实例。如果是数组还要有一块记录数组长度的数据。

    (3)访问定位:Java程序需要通过栈上的reference数据来操作堆上的具体对象,分为:

    【1】句柄访问,堆中分出一块内存作为句柄池,包括对象示例数据与类型数据各自的具体地址信息,reference中存储的是对象的句柄地址。好处是对象移动时只会改变句柄中的实例数据指针,reference本身不需要修改。

    

    【2】直接指针访问(常用),Java堆对象的布局中必须考虑如何放置访问类型数据的相关信息,reference存储对象地址,好处是速度更快,节省了一次指针定位的时间开销。

 

3、String.intern()

    native方法,如果常量池中存在当前字符串, 就会直接返回当前字符串; 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值