0%

句柄、直接指针

句柄是什么?

指针的指针。

jvm中内存里的对象都有一个指针指向对象的开始地址,句柄就是指向对象的指针。

句柄解决了什么问题?

对实际的对象资源做了一层代理,屏蔽细节,避免了直接操控资源可能的危险。

弄了句柄,对象实际位置在内存中可以随意变化,比如标记整理垃圾回收后对象被移动到其他地方。

虚拟内存机制,可能会将已经载入内存的数据换到外存硬盘上,这样对象的地址就会变动,其他地方引用这块被换走的地址也要更新,如果使用这块数据的地方引用的是句柄,这样实际数据在内存的位置可以随意变化,使用数据的地方还是引用固定的地址,不用更新。

Windows系统中有许多内核对象(这里的对象不完全等价于”面向对象程序设计”一词中的”对象”,虽然实质上还真差不多),比如打开的文件,创建的线程,程序的窗口,等等。这些重要的对象肯定不是4个字节或者8个字节足以完全描述的,他们拥有大量的属性。为了保存这样一个”对象”的状态,往往需要上百甚至上千字节的内存空间,那么怎么在程序间或程序内部的子过程(函数)之间传递这些数据呢?拖着这成百上千的字节拷贝来拷贝去吗?显然会浪费效率。那么怎么办?当然传递这些对象的首地址是一个办法,但这至少有两个缺点:

  1. 暴露了内核对象本身,使得程序(而不是操作系统内核)也可以任意地修改对象地内部状态(首地址都知道了,还有什么不能改的?),这显然是操作系统内核所不允许的;

  2. 操作系统有定期整理内存的责任,如果一些内存整理过一次后,对象被搬走了怎么办?

所以,Windows操作系统就采用进一步的间接(可以理解为进一步的抽象的过程):在进程的地址空间中设一张表,表里头专门保存一些编号和由这个编号对应一个地址,而由那个地址去引用实际的对象,这个编号跟那个地址在数值上没有任何规律性的联系,纯粹是个映射而已。

在Windows系统中,这个编号就叫做”句柄”。

参考:
句柄的概念

为什么叫句柄这个名字?

从名字上说,handle是指中间媒介,例如门把手是door handle,刀柄是knife handle。

所以文件句柄file handle以即其他资源句柄,也是这个中间媒介的意思,通过这个媒介操作资源。

参考:

JVM对象访问定位

JVM通过栈上的reference类型数据来操作堆上的具体对象。

由于reference数据只是规定了一个指向对象的引用,没有定义如何去定位访问对象的具体位置。

主流的实现方式有两种:

  • 句柄
    在堆中划分句柄池,reference存储对象的句柄地址,句柄包含对象实例数据和类型数据的各自具体地址信息。
    • 好处:reference中的数据是稳定的句柄地址 对象被移动只会改变句柄中的信息 不会改变句柄的地址 reference不需要变化。
    • 坏处:增加了指针定位的开销。
  • 直接指针
    栈上reference类型数据槽中直接存储堆对象的地址。
    • 好处:直接访问对象 减少指针定位开销。
    • 坏处:当对象内存地址发生变化 reference中数据也需要调整。

参考:

  • 《深入理解Java虚拟机(第2版)》 2.3.3 对象的访问定位 48页