JVM:堆中对象的创建?定位?可达性?

版权声明:本博客为记录本人学习过程而开,内容大多从网上学习与整理所得,若侵权请告知! https://blog.csdn.net/Fly_as_tadpole/article/details/87655457

对象的创建

java对象创建流程

指针碰撞:若是堆中的内存是绝对规整的,所有用过的内存放在一边,空闲的放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。

指针碰撞要求堆中所采用的GC搜集器是带有“压缩整理”功能的!

空闲列表:与指针碰撞相反,堆的内存空间是无序的,已使用内存和空闲内存交错,那便要使用一个空闲列表来记录堆中空闲内存的情况!根据空闲列表来分配空闲内存。

当对象访问十分频繁,且在多线程并发情况下,还要考虑内存指针的同步问题!?

两种方案:一种是基于CAS的同步方式保证操作原子性;另一种是TLAB(本地线程缓冲区),也即是提前在堆中为每个线程划分一小块内存,这样一来后来内存的分配可按照各线程在不同的TLAB中进行,起到隔离作用!


对象的定位

Pojo a = new Pojo();

a引用作为局部变量存在栈中,Pojo实例对象存在堆中,Pojo类型数据存在方法区。

a如何定位到堆中的对象呢?

1)句柄

2)直接指针

所谓句柄就是,在堆中维护一个句柄池,a引用指向句柄池中的某一个句柄,而这个句柄里面存着一个堆中对象实例的地址和一个方法区中类信息的地址。

所谓直接指针就是,a引用直接指向堆中的实例对象数据,在这个实例对象中存在一个指向方法区的类信息的指针。

使用句柄最大好处就是引用中存储的是稳定的句柄地址,在对象被移动时(例如GC),只会改变句柄中的实例对象的指针,而栈中的引用不需改变。

使用直接指针最大好处就是速度比较快,节省了一次指针定位的时间,适用于java对象访问频繁的场景。

可达性

可达性算法的基本思想是:通过一系列称为GCRoots的对象作为根节点,向下开始搜索,搜索所走过的路径成为引用链,当一个对象到GCRoots没有任何引用链相连的话,则证明该对象是不可用的,即为垃圾对象!

但是但是但是!!!!垃圾对象就一定是垃圾对象吗?不一定,垃圾对象可能会在finalize()结束之前复活!!!成为新的可用对象!!但是如果finalize()方法执行完之后,那么不可用对象就会都被回收!!!

finalize()方法只会被调用一次

分析:第一次gc时调用finalize()时,由于将this赋值给obj,导致obj重新获得引用,逃逸出F-QUEUE队列,成功拯救自己!

但是当第二次GC的时候,由于finalize()方法只会被调用一次,所以obj会被回收掉!!!

猜你喜欢

转载自blog.csdn.net/Fly_as_tadpole/article/details/87655457