句柄是什么?
指针的指针。
jvm中内存里的对象都有一个指针指向对象的开始地址,句柄就是指向对象的指针。
句柄解决了什么问题?
对实际的对象资源做了一层代理,屏蔽细节,避免了直接操控资源可能的危险。
弄了句柄,对象实际位置在内存中可以随意变化,比如标记整理垃圾回收后对象被移动到其他地方。
虚拟内存机制,可能会将已经载入内存的数据换到外存硬盘上,这样对象的地址就会变动,其他地方引用这块被换走的地址也要更新,如果使用这块数据的地方引用的是句柄,这样实际数据在内存的位置可以随意变化,使用数据的地方还是引用固定的地址,不用更新。
Windows系统中有许多内核对象(这里的对象不完全等价于”面向对象程序设计”一词中的”对象”,虽然实质上还真差不多),比如打开的文件,创建的线程,程序的窗口,等等。这些重要的对象肯定不是4个字节或者8个字节足以完全描述的,他们拥有大量的属性。为了保存这样一个”对象”的状态,往往需要上百甚至上千字节的内存空间,那么怎么在程序间或程序内部的子过程(函数)之间传递这些数据呢?拖着这成百上千的字节拷贝来拷贝去吗?显然会浪费效率。那么怎么办?当然传递这些对象的首地址是一个办法,但这至少有两个缺点:
暴露了内核对象本身,使得程序(而不是操作系统内核)也可以任意地修改对象地内部状态(首地址都知道了,还有什么不能改的?),这显然是操作系统内核所不允许的;
操作系统有定期整理内存的责任,如果一些内存整理过一次后,对象被搬走了怎么办?
所以,Windows操作系统就采用进一步的间接(可以理解为进一步的抽象的过程):在进程的地址空间中设一张表,表里头专门保存一些编号和由这个编号对应一个地址,而由那个地址去引用实际的对象,这个编号跟那个地址在数值上没有任何规律性的联系,纯粹是个映射而已。
在Windows系统中,这个编号就叫做”句柄”。
参考:
句柄的概念
为什么叫句柄这个名字?
从名字上说,handle是指中间媒介,例如门把手是door handle,刀柄是knife handle。
所以文件句柄file handle以即其他资源句柄,也是这个中间媒介的意思,通过这个媒介操作资源。
参考:
JVM对象访问定位
JVM通过栈上的reference类型数据来操作堆上的具体对象。
由于reference数据只是规定了一个指向对象的引用,没有定义如何去定位访问对象的具体位置。
主流的实现方式有两种:
- 句柄
在堆中划分句柄池,reference存储对象的句柄地址,句柄包含对象实例数据和类型数据的各自具体地址信息。- 好处:reference中的数据是稳定的句柄地址 对象被移动只会改变句柄中的信息 不会改变句柄的地址 reference不需要变化。
- 坏处:增加了指针定位的开销。
- 直接指针
栈上reference类型数据槽中直接存储堆对象的地址。- 好处:直接访问对象 减少指针定位开销。
- 坏处:当对象内存地址发生变化 reference中数据也需要调整。
参考:
- 《深入理解Java虚拟机(第2版)》 2.3.3 对象的访问定位 48页