遗留问题
String s2 = “dd” + new String(“test”);
四个 string
3个char
数组
UseCompressedoops
压缩的是对象指针的长度
UseCompressedClassPointers
压缩的是klass对象指针的长度
如果不压缩,则在arrayOopDesc中声明的非静态字段之后分配,如果压缩,它将占用oopDesc中_klass字段的后半部分。
数组长度怎么算
数组
对应的klass是:TypeArrayKlass实例
对应的oop:TypeArrayOop对象的内存布局
对象头 mark word klass pointer 实例数据 填充
不开启解压的情况:
Mark word 8B
klass point
metadata._compressed_klass
数组长度4B这种情况下,klass + 数组长度用了多少字节 12 = 8 + 4 开启压缩的情况下: _metadata._compressed_klass 数组长度4B klass + 数组长度= 4 + 4 = 8B
=====
垃圾回收算法
可重入锁很像 lock + 1 unlock -1 计数==0
释放
对象存活依据
引用计数
例外,无法处理循环依赖。
初始化死锁
可达性分析
GC Roots
oop
局部变量表
字符串常量池
JVM的GC
给存活的对象打标机,回收没有标记的对象。
内存池
内存分配算法
指针碰撞(openJdk, 无限CAS-失败就是已经被使用了 )空闲列表:维护一个表存放 已用,空闲,已回收 描述。
Memory Pool内存池
管理内存块。
list<MemoryChunk *> m_chunks;
是一个列表,存放所有向OS申请的内存块。能做的事情
向OS要内存
mall哦错,calloc
释放内存
没有垃圾回收器,需要手动释放其他
打印chunk信息
Memory chunk
直接持有内存Memory Cell
chunk中的单元。内存块。
Memory Pool
根据要的内存对齐后计算出要申请的内存大小。
向操作系统申请内存。
根据不同的垃圾回收算法填充不同的list
标记清除,标记-整理,回收的是整个chunk.m_avaliable_table m_used_table
分代+复制算法,
空闲
可用
已用
待交换
标记-清除算法
面向整个堆
产生碎片如果你需要分配大对象,需要连续的空间。但是内存是碎片化的。
标记-整理算法
内存碎片合并
老年代基本属于这个算法。合并内存,解决碎片问题。
耗CPUEden区,对象朝生夕死。碎片很多。
碎片很多,合并碎片的时候需要STW。合并碎片的时候有两种对象需要处理:
1. 这个空间已被释放。直接合并
2. 这个空间的空间未被释放
对象搬家(合并内存,数据移动,指针移动)分代-复制算法
JVM使用这个算法,解决标记合并碎片消耗性能过高、GC停止用户线程过长问题。
举例- 将内存分段。 一半用(0-10) from,一半闲(11-20)to
- 发生GC的时候不需要整理,交换空间标记,角色切换。
标记
角色切换
原先from区的内存处理
标记的对象清理。存活的对象需要移动到新的内存区域(to 区)
数据整理
指针整理
注意:
不管现在的9种垃圾回收器,还是以后出现的垃圾回收器,都是这三种垃圾回收算法。
指针移动,老的指针地址不能变,这个怎么做到?(对象的hashCode不变)
指针是动态计算出来的。
公式依赖的变量在变。
return (pvoid)((ulong)chunk->get_data() + get_start()* chunk->get_align_size() )
卡表,记忆集
总结
内存池,JVM不需要手动释放内存,由垃圾回收器自动回收。
自动回收算法
标记-清除算法。面向整个堆,会产生碎片,在申请大对象时候,会有问题。
标记-整理算法。老年代常用,会在标记清理后整理内存,但是CPU耗费太大,STW时间会比较长。
标记,清理,数据整理,指针整理。
数据块(chunk cell)整理过程
从前到后合并一次
从后到前合并一次
分代-复制
解决整理算法性能太低,而且新生代的特点是朝生夕死。
不需要清理,只需要转移数据和指针切换 from,to角色
问题:
指针切换了以后为什么可以访问?
hashcode会一直变。运行时计算出来的,所以没影响。
PS:对象模型,为什么要字节对齐。8B
CPU提升速率。
CPU读是 4
当数据从1字节开始的时候,问题很复杂,首先先将前4个字节读到寄存器,并再次读取4-7字节的数据进寄存器,接着把0字节,4,6,7字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器,对一个内存未对齐的寄存器进行了这么多额外操作,大大降低了CPU的性能。
但是这还属于乐观情况,上文提到内存对齐的作用之一是平台的移植原因,因为只有部分CPU肯干,其他部分CPU遇到未对齐边界就直接罢工了。