GCC如何在内存中存储成员函数? [英] How does GCC store member functions in memory?

查看:209
本文介绍了GCC如何在内存中存储成员函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想尽量减少我的类在内存中占用的大小(数据和指令)。我知道如何最小化数据大小,但我不太熟悉GCC如何放置成员函数。



它们存储在内存中,它们在class

解决方案

为了内存中数据表示的目的,C ++ class 可以具有普通或静态成员函数,或 virtual 成员函数(包括一些 virtual 析构函数)。



普通或静态成员函数在数据存储器中不占用任何空间,但是它们的编译代码当然需要一些资源,例如作为文本中的二进制代码或可执行文件或过程的代码段。当然,他们还可以在 static 数据(或线程本地数据)或本地数据(例如局部变量) .wikipedia.org / wiki / Call_stackrel =nofollow>调用堆栈



我的答案是面向Linux。我不知道Windows,不知道GCC如何工作。



虚拟成员函数通常通过虚拟方法表(或 vtable );具有一些虚拟成员函数的类 c>通常具有单个实例(假设single- 继承)vtable指针指向该vtable(这实际上是一些数据包装在文本段)。



请注意,vtables不是强制性的,不是C ++ 11标准所必需的。但是我不知道任何不使用它们的C ++实现。



当你使用多重继承事情变得更加复杂,对象可能有几个vtable指针。



因此,如果你有一个(一个根类或使用单继承),虚函数成员函数的消耗是一个vtable每个实例的指针(加上单个vtable本身所需的小空间)。它不会改变(对于每个实例),如果你只有一个虚拟成员函数(或析构函数)或一千个(什么会改变是vtable本身)。每个类都有自己的单个 vtable(除非没有虚拟成员函数),每个实例通常有一个(单继承情况)vtable指针。



GCC编译器可以根据需要自由组织vtable(它的顺序和布局是你不应该关心的实现细节)。另请参阅。在实践中(对于单继承),对于大多数最近的GCC版本,vtable指针是对象的第一个单词,vtable包含函数指针,按照虚拟方法声明的顺序,但是你不应该依赖这些细节。 p>

GCC编译器可以根据需要自由地组织代码段中的函数,并且实际上会重新排序它们(例如优化)。上次我看,它命令他们倒序。但你肯定不应该依赖于这个顺序! BTW GCC可以在优化时内联函数(即使未标记为 inline )和克隆函数。您还可以通过链接时间优化(例如 code> make CXX ='g ++ -flto -Os'),您可以要求个人资料引导的优化(适用于 GCC < a>: -fprofile-generate -fprofile-use -fauto-profile etc ...)



您不应该依赖于编译器函数代码或 vtables 保留对编译器的优化(这种优化取决于目标机器,编译器标志和编译器版本)。您还可以使用函数属性向GCC(或Clang)提供提示/ LLVM)编译器(例如 __ attribute __((cold)) __ attribute __((noinline)) 。)



如果你真的需要知道函数如何放置(IMHO是非常错误的),请研究生成的汇编代码(例如使用 g ++



如果您需要在Linux和Posix系统上在运行时从其名称中查找函数的地址,请考虑使用 dlsym (对于Linux,请参见 dlsym(3),其中也包括 dladdr )。请注意名称管理,您可以通过声明此类函数来禁用名称管理 externC(请参阅 C ++ dlopen minihowto )。

BTW,您可以编译并链接到 -rdynamic (这对于 dlopen etc ...)。如果您真的需要知道函数的地址,请使用 nm(1)作为 nm -C 您的可执行文件



ABI 规范和调用约定您的目标平台(和编译器),例如 Linux x86-64 ABI规范


I am trying to minimise the size my class occupies in memory (both data and instructions). I know how to minimise data size, but I am not too familiar with how GCC places member functions.

Are they stored in memory, the same order they are declared in the class?

解决方案

For the purpose of in-memory data representation, a C++ class can have either plain or static member functions, or virtual member functions (including some virtualdestructor, if any).

Plain or static member functions do not take any space in data memory, but of course their compiled code take some resource, e.g. as binary code in the text or code segment of your executable or your process. Of course, they can also require static data (or thread-local data), or local data (e.g. local variables) on the call stack.

My answer is Linux oriented. I don't know Windows, and don't know how GCC work on it.

Virtual member functions are very often implemented thru virtual method table (or vtable); a class having some virtual member functions usually have instances with a single (assuming single-inheritance) vtable-pointer pointing to that vtable (which is practically some data packed in the text segment).

Notice that vtables are not mandatory and are not required by C++11 standard. But I don't know any C++ implementation not using them.

When you are using multiple-inheritance things become more complex, objects might have several vtable pointers.

So if you have a class (either a root class, or using single-inheritance), the consumption for virtual member functions is one vtable pointer per instance (plus the small space needed by the single vtable itself). It won't change (for each instance) if you have only one virtual member function (or destructor) or a thousand of them (what would change is the vtable itself). Each class has its own single vtable (unless it has no virtual member function), and each instance has generally one (for single-inheritance case) vtable pointer.

The GCC compiler is free to organize the vtable as it wishes (and its order and layout is an implementation detail you should not care about); see also this. In practice (for single-inheritance) for most recent GCC versions, the vtable pointer is the first word of the object, and the vtable contain function pointers in the order of virtual method declaration, but you should not depend on such details.

The GCC compiler is free to organize the functions in the code segment as it wishes, and it would actually reorder them (e.g. for optimizations). Last time I looked, it ordered them in reverse order. But you certainly should not depend on that order! BTW GCC can inline functions (even when not marked inline) and clone functions when optimizing. You could also compile and link with link-time optimizations (e.g. make CXX='g++ -flto -Os'), and you could ask for profile-guided optimizations (for GCC: -fprofile-generate, -fprofile-use, -fauto-profile etc...)

You should not depend on how the compiler (and linker) is organizing function code or vtables. Leave the optimizations to the compiler (and such optimizations depend upon your target machine, your compiler flags, and the compiler version). You might also use function attributes to give hints to the GCC (or Clang/LLVM) compiler (e.g. __attribute__((cold)), __attribute__((noinline)) etc etc....)

If you really need to know how functions are placed (which IMHO is very wrong), study the generated assembly code (e.g. using g++ -O -fverbose-asm -S) and be aware that it could vary with compiler versions!

If you need on Linux and Posix systems at runtime to find out the address of a function from its name, consider using dlsym (for Linux, see dlsym(3), which also documents dladdr). Be aware of name mangling, which you can disable by declaring such functions as extern "C" (see C++ dlopen minihowto).

BTW, you might compile and link with -rdynamic (which is very useful for dlopen etc...). If you really need to know the address of functions, use nm(1) as nm -C your-executable.

You might also read the ABI specification and calling conventions for your target platform (and compiler), e.g. Linux x86-64 ABI spec.

这篇关于GCC如何在内存中存储成员函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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