对象引用与内存地址的关联

疑问:

在学习GC的时候发现,无论是Mark and Copy,还是Mark-Sweep-Compact算法,都要移动对象,这必然会导致对象的内存地址发生变动,那么移动后,对象是怎么找到在heap中对象的新内存地址的?

难道移动对象的时候会将引用这个对象的所有变量的值更新?

垃圾收集算法:https://plumbr.io/handbook/garbage-collection-algorithms

深入理解JVM中的解答:

《深入理解Java虚拟机》第2版中,第2章的2.3.3 对象的访问定位中提到,对象访问方式目前主流有两种:

  • 句柄
  • 直接指针

句柄:

如果使用句柄访问的话,那么Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体信息。

使用句柄来访问的最大好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。

img

网上解答:

对象引用: https://www.artima.com/insidejvm/ed2/jvm6.html

Object Representation

......

One possible heap design divides the heap into two parts: a handle pool and an object pool. An object reference is a native pointer to a handle pool entry. A handle pool entry has two components: a pointer to instance data in the object pool and a pointer to class data in the method area. The advantage of this scheme is that it makes it easy for the virtual machine to combat heap fragmentation. When the virtual machine moves an object in the object pool, it need only update one pointer with the object's new address: the relevant pointer in the handle pool. The disadvantage of this approach is that every access to an object's instance data requires dereferencing two pointers. This approach to object representation is shown graphically in Figure 5-5. This kind of heap is demonstrated interactively by the HeapOfFish applet, described in Chapter 9, "Garbage Collection."

img

Figure 5-5. Splitting an object across a handle pool and object pool.

简单翻译:

一种可能的堆设计,将堆分为两部分:

  • 句柄池
  • 对象池

一个对象引用是指向句柄池中一个条目(元素)的原始指针。

一个句柄池条目有两个组成部分:一个指向对象池中实例数据的指针和一个指向方法区中类数据的指针。

这种方案的优势在于:它使虚拟机可以轻松应对堆碎片(不连续的可用内存区域)。 当虚拟机在对象池中移动对象时,只需要更新句柄池中相关对象的指针。

这种方法的缺点是:每次访问对象都需要进行两次指针定位。

压缩收集器: https://www.artima.com/insidejvm/ed2/gc5.html

Compacting Collectors

......

Updating references to moved objects is sometimes made simpler by adding a level of indirection to object references. Instead of referring directly to objects on the heap, object references refer to a table of object handles. The object handles refer to the actual objects on the heap. When an object is moved, only the object handle must be updated with the new location. All references to the object in the executing program will still refer to the updated handle, which did not move. While this approach simplifies the job of heap defragmentation, it adds a performance overhead to every object access.

简单翻译:

通过向对象引用添加中间层,有时可以使更新移动对象的引用变得更加简单。 对象引用不是直接引用堆上的对象,而是引用对象句柄表。 对象句柄再引用堆上的实际对象。 当移动对象时,只需要使用新的位置来更新对象句柄即可。 在运行的程序中对对象的所有引用仍然可以关联到更新后的句柄,该句柄的内存地址不会移动。 尽管此方法简化了堆碎片的整理工作,但它增加了每个对象访问的性能开销。

猜你喜欢

转载自www.cnblogs.com/demojie/p/12273935.html