(这是关于软件设计一个相当大的问题。如果它不适合StackOverflow的我愿意把它复制到软件工程社区)
我与heap_stat,脚本,负责调查工作的转储。这个脚本是基于,对于具有虚函数的任何对象,则vftable
场总是第一个(允许查找类对象的内存地址)的想法。
在我的应用程序有一些对象,有vftable
项(通常每STL
对象有它),但也有相当长的一段对象谁不知道。
为了强制vftable
场的存在,我已经做了如下测试:
创建一个类的废话,具有虚拟功能,并让我的类从这个废话类继承:
class NONSENSE {
virtual int nonsense() { return 0; }
};
class Own_Class : public NONSENSE, ...
这符合市场预期,创造了符号,这是我能找到的(使用vftable
的Windbg
命令)一个x /2 *!Own_Class*vftable*
条目:
00000000`012da1e0 Own_Application!Own_Class::`vftable'
我还看到在内存使用情况的差异:
sizeof(an normal Own_Class object) = 2928
sizeof(inherited Own_Class object) = 2936
=> 8个字节已经添加了该对象。
这里有一个问题:显然颇有些对象定义为:
class ATL_NO_VTABLE Own_Class
此ATL_NO_VTABLE
块vftable
条目,这意味着下面的创建(ATL_NO_VTABLE
等于__declspec(novtable)
):
// __declspec(novtable) is used on a class declaration to prevent the vtable
// pointer from being initialized in the constructor and destructor for the
// class. This has many benefits because the linker can now eliminate the
// vtable and all the functions pointed to by the vtable. Also, the actual
// constructor and destructor code are now smaller.
在我看来,这意味着vftable
还没有生成,因为这些对象的方法被调用更直接,其对方法执行和协议栈处理的速度产生影响。允许创建的vftable
有以下影响:
为了不被考虑在内:
要考虑到:
现在我有以下问题:
vftable
磁场的形成,其影响更小?提前致谢
难道我的影响分析是正确的?
第__declspec(novtable)
省略代虚函数表本身的给定类,则指向VTABLE仍然存在,所以的sizeof不会改变。
__declspec(novtable)
是指将用于基类,已经派生类。因此派生类的构造函数是虚函数表将指针设置导出虚函数表,并且不需要基地虚函数表。
所以,这种优化消除了一个指针赋值(在构造函数代码生成的一部分),并为虚函数表本身一点空间。不是很有益的你的目标是有每个对象的优化,它只做小每级优化。
它会工作,如果你没有自己的创造基地的情况下,不调用构造函数/析构虚方法。
通过使这些非虚虚函数调用的遗漏是完全独立的故事。这就是所谓的devirtualization。当编译器可以肯定的实例,它是采用类,它取代非虚拟的虚拟电话。
__declspec(novtable)
不禁devirtualization进不去。 final
/ sealed
关键字可以帮助devirtualization,因为他们说有没有进一步的派生类/方法。
对于假设虚函数表指针是第一个成员,这可能是错误的。虚表指针会不会首先,如果你的基类没有虚函数表,但有一些数据成员。也有可能不止一个虚函数表指针。
分析结构在转储程序,我会建议使用合适的API。有两个API:DIA SDK和dbghelp functions。它们是相似的,但第一个是基于对象的(COM)和第二只是平坦的API,所以第一可更容易使用。
正如heap_stat脚本的做法本质上是有限的,我会建议堆分析使用UMDH相反,它不依赖于虚函数表的所有,并显示所有类型的对象
在此期间,我发现一个非常简单的方法来强制每类vftable'
条目:刚刚宣布每析构函数为虚。
为了找到所有的析构函数,谁不是虚拟的是,我已经推出了以下在我的开发目录内我的Ubuntu的应用程序的命令:
find ./ -name "*.h" -exec fgrep "~" {} /dev/null \; | grep -v "virtual"
在已经宣布所有析构函数为虚,我打算做一些性能测试(我认为声明的方法,虚可能对速度产生影响,如方法声明已经改变,尤其是对于重负载的服务器应用程序),我会保持这个贴子是最新的。