在windbg“x/2"中强制执行vftable条目结果,要考虑什么? [英] Enforcing a vftable entry in windbg "x /2" results, what to consider?

查看:63
本文介绍了在windbg“x/2"中强制执行vftable条目结果,要考虑什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

为了强制存在 vftable 字段,我做了以下测试:

创建一个无意义的类,有一个虚函数,让我的类继承这个无意义的类:

class NONSENSE {virtual int nonsense() { return 0;}};类 Own_Class :公共无意义,...

正如预期的那样,这在符号中创建了一个 vftable 条目,我可以找到它(使用 Windbgx/2 *!Own_Class*vftable* 命令):

00000000`012da1e0 Own_Application!Own_Class::`vftable'

我还看到了内存使用量的差异:

sizeof(一个普通的 Own_Class 对象) = 2928sizeof(继承的Own_Class对象)=2936

=> 已为此对象添加了 8 个字节.

有一个问题:显然有些对象被定义为:

class ATL_NO_VTABLE Own_Class

这个 ATL_NO_VTABLE 阻止了 vftable 条目的创建,这意味着以下 (ATL_NO_VTABLE 等于 __declspec(novtable)):

//__declspec(novtable) 用于类声明以防止 vtable//在构造函数和析构函数中初始化的指针//班级.这有很多好处,因为链接器现在可以消除//vtable 以及 vtable 指向的所有函数.另外,实际//构造函数和析构函数代码现在更小了.

在我看来,这意味着没有创建vftable,因为它更直接地调用对象方法,从而影响方法执行和堆栈处理的速度.允许创建 vftable 有以下影响:

不考虑:

  • 堆栈上还有一个调用,这仅对已经达到内存使用限制的系统产生影响.(我不知道链接器如何指向特定方法)
  • CPU 使用率的增加幅度太小,无法看到.
  • 速度下降幅度太小而无法看到.

需要考虑:

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

现在我有以下问题:

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

提前致谢

解决方案

与此同时,我发现了一种非常简单的方法来强制每个类的 vftable' 条目:只需将每个析构函数声明为虚拟的.

为了找到所有尚未虚拟的析构函数,我在我的开发目录中的 Ubuntu 应用程序中启动了以下命令:

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

在将所有析构函数声明为虚拟之后,我打算进行一些性能测试(我相信将方法声明为虚拟可能会对速度产生影响,因为方法声明已更改,特别是对于服务器应用程序负载很重),我会及时更新这篇文章.

(This is quite a large question about software design. In case it's not suited for StackOverflow I'm willing to copy it to the Software-Engineering community)

I'm working with heap_stat, a script, which investigates dumps. This script is based on the idea that, for any object which has a virtual function, the vftable field is always the first one (allowing to find the memory address of the class of the object).

In my applications there are some objects, having vftable entries (typically every STL object has it), but there are also quite some objects who don't.

In order to force the presence of a vftable field, I've done following test:

Create a nonsense class, having a virtual function, and let my class inherit from this nonsense class:

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

class Own_Class : public NONSENSE, ...

This, as expected, created a vftable entry in the symbols, which I could find (using Windbg's x /2 *!Own_Class*vftable* command):

00000000`012da1e0 Own_Application!Own_Class::`vftable'

I also saw a difference in memory usage:

sizeof(an normal Own_Class object) = 2928
sizeof(inherited Own_Class object) = 2936

=> 8 bytes have been added for this object.

There's a catch: apparently quite some objects are defined as:

class ATL_NO_VTABLE Own_Class

This ATL_NO_VTABLE blocks the creation of the vftable entry, which means the following (ATL_NO_VTABLE equals __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.

In my opinion, this means that the vftable does not get created, because of which object methods get called more directly, having an impact on the speed of the method execution and stack handling. Allowing the vftable to be created has following impact:

Not to be taken into account:

  • There is one more call on the stack, this only has impact in case of systems which are already at the limit of their memory usage. (I have no idea how the linker points to a particular method)
  • The CPU usage increase will be too small to be seen.
  • The speed decrease will be too small to be seen.

To be taken into account:

  • As mentioned before, the memory usage of the application increases by 8 bytes per object. When a regular object has a size of some 1000 bytes, this means a memory usage increase of ±1%, but for objects with a memory size of less than 80 bytes, this might cause a memory usage increase of +10%.

Now I have following questions:

  1. Is my analysis on the impact correct?
  2. Is there a better way to force the creation of the vftable field, having less impact?
  3. Did I miss anything?

Thanks in advance

解决方案

In the meantime, I've found a terribly easy way to force vftable' entries for every class: just declare every destructor as virtual.

In order to find all destructors, who are not virtual yet, I've launched following command in my Ubuntu app within my development directory:

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

After having declared all destructors as virtual, I'm planning to do some performance testing (I believe that declaring a method as virtual might have an impact on the speed, as the method declaration has been changed, especially for a server application with heavy load), I'll keep this post up to date.

这篇关于在windbg“x/2"中强制执行vftable条目结果,要考虑什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆