gpt4 book ai didi

c++ - 在 windbg "x/2"结果中强制执行 vftable 条目,需要考虑什么?

转载 作者:太空宇宙 更新时间:2023-11-04 12:40:25 27 4
gpt4 key购买 nike

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

我正在使用 heap_stat,一个调查转储的脚本。这个脚本基于这样的想法,对于任何具有虚函数的对象,vftable 字段总是第一个(允许找到对象类的内存地址)。

在我的应用程序中,有一些对象具有 vftable 条目(通常每个 STL 对象都有),但也有相当多的对象没有。

为了强制出现vftable 字段,我做了以下测试:

创建一个废话类,有一个虚函数,让我的类继承这个废话类:

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

class Own_Class : public NONSENSE, ...

正如预期的那样,这在符号中创建了一个 vftable 条目,我可以找到它(使用 Windbgx/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 具有以下影响:

不予考虑:

  • 堆栈上还有一个调用,这只对内存使用量已经达到极限的系统有影响。 (我不知道链接器是如何指向特定方法的)
  • CPU 使用率的增加将小到看不见。
  • 速度下降幅度小到看不见。

要考虑:

  • 如前所述,应用程序的内存使用量每个对象增加 8 个字节。当一个常规对象的大小为 1000 字节左右时,这意味着内存使用量增加了 ±1%,但对于内存大小小于 80 字节的对象,这可能会导致内存使用量增加 +10%。<

现在我有以下问题:

  1. 我对影响的分析是否正确?
  2. 是否有更好的方法来强制创建 vftable 字段且影响较小?
  3. 我错过了什么吗?

提前致谢

最佳答案

Is my analysis on the impact correct?

没有。 __declspec(novtable) 省略了给定类的 vtable 本身 的生成,指向 vtable 的指针 仍然存在,因此 sizeof 不会改变。

__declspec(novtable) 用于具有派生类的基类。这样派生类的构造函数会将vtable指针设置为派生vtable,而不需要基vtable。

因此,这种优化消除了一个指针赋值(在构造函数代码的生成部分),并为 vtable 本身留出了一点空间。 针对每个对象 的优化对于您的目标不是很有用,因为它只进行较小的针对每个类 优化。

如果您不自己创建基础实例,并且不在构造函数/析构函数中调用虚方法,它就会起作用。

通过使它们成为非虚函数来省略虚函数调用是完全不同的故事。它被称为去虚拟化。当编译器可以确定使用了哪个类的实例时,它会将虚拟调用替换为非虚拟调用。

__declspec(novtable) 无论如何都无法帮助去虚拟化。 final/sealed 关键字可能有助于去虚拟化,因为他们说没有进一步的派生类/方法。

关于 vtable 指针是第一个成员的假设,这可能是错误的。如果您的基类没有 vtable,但有一些数据成员,vtable 指针将不是第一个。也可能有不止一个虚表指针。

要以编程方式分析转储中的结构,我建议使用适当的 API。有两个 API:DIA SDKdbghelp functions .它们很相似,但第一个是基于对象的 (COM),第二个只是平面 API,因此第一个可能更易于使用。

由于 heap_stat 脚本的方法本质上是有限的,我建议堆分析使用 UMDH相反,它完全不依赖 vtable,并显示各种对象

关于c++ - 在 windbg "x/2"结果中强制执行 vftable 条目,需要考虑什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54481737/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com