强制在WinDbg中的“X / 2”结果vftable项,要考虑什么?

问题描述 投票:1回答:2

(这是关于软件设计一个相当大的问题。如果它不适合StackOverflow的我愿意把它复制到软件工程社区)

我与heap_stat,脚本,负责调查工作的转储。这个脚本是基于,对于具有虚函数的任何对象,则vftable场总是第一个(允许查找类对象的内存地址)的想法。

在我的应用程序有一些对象,有vftable项(通常每STL对象有它),但也有相当长的一段对象谁不知道。

为了强制vftable场的存在,我已经做了如下测试:

创建一个类的废话,具有虚拟功能,并让我的类从这个废话类继承:

class NONSENSE {
    virtual int nonsense() { return 0; }
};

class Own_Class : public NONSENSE, ...

这符合市场预期,创造了符号,这是我能找到的(使用vftableWindbg命令)一个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_VTABLEvftable条目,这意味着下面的创建(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有以下影响:

为了不被考虑在内:

  • 还有就是堆在一个多个呼叫,这只有在其已经在他们的内存使用量的限制系统情况的影响。 (我不知道如何链接指向一个特定的方法)
  • CPU使用率的增加将是太小待观察。
  • 速度下降将是太小待观察。

要考虑到:

  • 如前所述,由每个对象8个字节的应用的增加的存储器使用量。当一个常规的对象的大小的一些1000个字节,这意味着的±1%的内存使用情况增加,但对于具有小于80个字节的存储器大小的对象,这可能导致的+ 10%的存储器使用量的增加。

现在我有以下问题:

  1. 难道我的影响分析是正确的?
  2. 有没有更好的办法迫使vftable磁场的形成,其影响更小?
  3. 我错过了什么?

提前致谢

c++ memory-management windbg virtual-functions
2个回答
0
投票

难道我的影响分析是正确的?

__declspec(novtable)省略代虚函数表本身的给定类,则指向VTABLE仍然存在,所以的sizeof不会改变。

__declspec(novtable)是指将用于基类,已经派生类。因此派生类的构造函数是虚函数表将指针设置导出虚函数表,并且不需要基地虚函数表。

所以,这种优化消除了一个指针赋值(在构造函数代码生成的一部分),并为虚函数表本身一点空间。不是很有益的你的目标是有每个对象的优化,它只做小每级优化。

它会工作,如果你没有自己的创造基地的情况下,不调用构造函数/析构虚方法。

通过使这些非虚虚函数调用的遗漏是完全独立的故事。这就是所谓的devirtualization。当编译器可以肯定的实例,它是采用类,它取代非虚拟的虚拟电话。

__declspec(novtable)不禁dev​​irtualization进不去。 final / sealed关键字可以帮助devirtualization,因为他们说有没有进一步的派生类/方法。

对于假设虚函数表指针是第一个成员,这可能是错误的。虚表指针会不会首先,如果你的基类没有虚函数表,但有一些数据成员。也有可能不止一个虚函数表指针。

分析结构在转储程序,我会建议使用合适的API。有两个API:DIA SDKdbghelp functions。它们是相似的,但第一个是基于对象的(COM)和第二只是平坦的API,所以第一可更容易使用。

正如heap_stat脚本的做法本质上是有限的,我会建议堆分析使用UMDH相反,它不依赖于虚函数表的所有,并显示所有类型的对象


0
投票

在此期间,我发现一个非常简单的方法来强制每类vftable'条目:刚刚宣布每析构函数为虚。

为了找到所有的析构函数,谁不是虚拟的是,我已经推出了以下在我的开发目录内我的Ubuntu的应用程序的命令:

find ./ -name "*.h" -exec fgrep "~" {} /dev/null \; | grep -v "virtual"

在已经宣布所有析构函数为虚,我打算做一些性能测试(我认为声明的方法,虚可能对速度产生影响,如方法声明已经改变,尤其是对于重负载的服务器应用程序),我会保持这个贴子是最新的。

© www.soinside.com 2019 - 2024. All rights reserved.