zoukankan      html  css  js  c++  java
  • Delphi高手突破第二章(4),VMT与DMT

    ==============================VMT===================================

    在创建一个类的实例之后,编译器在该对象的内存空间的首4个字节安插一个指针,该指针指向的地址称为VMT(Virtual Method Table,虚方法表),这个表中放了该类的所有虚方法的入口地址。

    在Object Pascal中,所有类实例都会有这么一个指向VMT的指针。如果没有在类中声明虚方法,则该指针为nil。
    没有被派生类赋给的方法,编译器会将基类的该方法实现的入口地址填入派生类的VMT中。

    其实“指向VMT的指针”所指向的VMT,其实只是真正VMT的一部分,也就是用户定义的第一个虚方法的位置。如果以这个位置为原点,向正方向即刚才所说的VMT,而向负方向,则是语言定义的另一些信息所在地址,析构函数地址就被放在了负方向上了。所以VMT中也有析构函数,但没有出现在我们所能见到的VMT中。这样做的目的,是为了与C++以及COM的VMT相兼容。

    据观察:负方向包括7个TObject的虚函数(包括析构函数,位置-4),以及指向其它表格的指针(虚方法表, 接口表, Automation information table, 实例初始化表, 类型信息表,属性表, 方法表, DMT(动态方法表), 类名, 实例大小,指向祖先类指针,安全异常指针)

    ==============================DMT====================================

    VMT的-48处是一个指向DMT的指针,它与VMT有什么关系?

    派生类的虚方法表完全继承了基类的虚方法表,只是将被覆盖的虚方法地址变了。基类和每个派生类都有一份自己的虚方法表。可以想象,随着类层次的扩展,虚方法将耗费非常大的内存空间。为了防止这种情况,Object Pascal引入了“dynamic”的概念。dynamic和virtual方法实现相同的功能,只有声明的关键字不同。被声明为dynamic的方法,其入口地址将被放在DMT中。

    VMT和DMT的区别在于:对于派生类没有覆盖的方法,这些方法的入口地址不会出现在DMT中,编译器要通过基类的信息来寻找它们的入口地址。

    DMT中不会出现没有被派生类覆盖的基类dynamic方法,因此DMT会比VMT节省空间,但是DMT中对基类的动态方法的寻址不是直接进行的,因此dynamic要比virtual要慢一些。当基类有许多虚方法,而派生类只覆盖很少几个时,区别尤其明显。当派生层次越来越深,派生数量越来越多时,DMT就能节省更多的内存空间。virtual与dynamic的区别仅在于编译器采用不同的晚绑定策略而已,对于程序员而言,它们的功能相同。

    几乎每个派生类都要覆盖的方法,将它声明为virtual;
    如果层次很深,或者派生类很多,但某个方法只被很少的派生类赋给,则声明为dynamic。

    另外需要注意的是,只有VMT才与C++、COM的vtable兼容。如果需要这样的兼容性时,只能使用virtual。

  • 相关阅读:
    Java深入学习31:ArrayList并发异常以及解决方案
    Java深入学习30:CAS中的ABA问题以及解决方案
    Java深入学习29:线程等待和唤醒的两个方案
    Redis学习05:Springboot集成Redis集群cluster
    项目总结66:Springboot项目继承kafka集群
    项目总结65:内存溢出OOM问题处理
    异常处理009:Windows10远程桌面连接提示:出现身份验证错误,要求的函数不受支持
    项目总结64:分别使用Redisson和Zookeeper分布式锁模拟模拟抢红包业务
    项目总结63:使用Spring AOP和BindingResult实现对接口的请求数据校验,并用@ExceptionHandler返回校验结果
    Java深入学习04:深入理解HashMap
  • 原文地址:https://www.cnblogs.com/findumars/p/2629563.html
Copyright © 2011-2022 走看看