GCC如何在内存中存储成员函数
How does GCC store member functions in memory?
我试图最小化我的类在内存中占用的大小(数据和指令)。我知道如何最小化数据大小,但我不太熟悉GCC如何放置成员函数。
是否按照在类中声明的顺序存储在内存中?
为了在内存中表示数据,c++ class
可以有普通成员函数或静态成员函数,也可以有virtual
成员函数(包括一些virtual
析构函数,如果有的话)。
普通或静态成员函数在数据内存中不占用任何空间,但是它们编译的代码当然会占用一些资源,例如,作为可执行文件或进程的文本或代码段中的二进制代码。当然,它们也可以需要static
数据(或线程本地数据),或调用堆栈上的本地数据(例如本地变量)。
我的答案是面向Linux的。我不懂Windows,也不知道GCC是怎么工作的
虚成员函数通常通过虚方法表(或vtable)实现;具有一些虚成员函数的class
通常具有单个(假设单继承)虚表指针的实例,该虚表指针指向该虚表(实际上是打包在文本段中的一些数据)。
注意,变量不是强制性的,c++ 11标准也不要求它。
当您使用多重继承时,事情变得更加复杂,对象可能具有多个虚函数表指针。
因此,如果您有一个class
(根类或使用单继承),则虚拟成员函数的消耗是每个实例一个虚值表指针(加上单个虚值表本身所需的小空间)。如果你只有一个虚成员函数(或析构函数)或一千个这样的虚成员函数(改变的是虚函数表本身),它不会改变(对于每个实例)。每个类都有自己的单个虚值表(除非它没有虚成员函数),并且每个实例通常有一个虚值表指针(对于单继承情况)。
GCC编译器可以自由地组织虚值表(它的顺序和布局是你不应该关心的实现细节);再看看这个。在大多数最新的GCC版本中(对于单继承),虚函数表指针是对象的第一个字,虚函数表按照虚方法声明的顺序包含函数指针,但您不应该依赖于这些细节。
GCC编译器可以自由地组织代码段中的函数,它实际上会重新排序它们(例如为了优化)。上次我看的时候,它们是倒序排列的。但是你当然不应该依赖这个顺序!顺便说一句,GCC可以在优化时内联函数(即使没有标记为inline
)和克隆函数。你也可以编译和链接与链接时优化(例如make CXX='g++ -flto -Os'
),你可以要求配置文件引导的优化(对于GCC: -fprofile-generate
, -fprofile-use
, -fauto-profile
等…)
你不应该依赖于编译器(和链接器)如何组织函数代码或虚表。将优化留给编译器(这种优化取决于您的目标机器、编译器标志和编译器版本)。你也可以使用函数属性给GCC(或Clang/LLVM)编译器(例如__attribute__((cold))
, __attribute__((noinline))
等....)提示
如果你真的需要知道函数是如何放置的(我认为这是非常错误的),研究生成的汇编代码(例如使用g++ -O -fverbose-asm -S
),并意识到它可能因编译器版本而异!
如果您需要在Linux和Posix系统上在运行时从函数的名称中查找函数的地址,请考虑使用dlsym(对于Linux,请参阅dlsym(3),它也记录了dladdr
)。注意名称混淆,可以通过声明extern "C"
这样的函数来禁用它(参见c++ dlopen minihowto)。
BTW,你可以编译和链接-rdynamic
(这是非常有用的dlopen
等…)。如果你真的需要知道函数的地址,使用nm(1)作为nm -C
your-executable。
您也可以阅读针对目标平台(和编译器)的ABI规范和调用约定,例如Linux x86-64 ABI规范。
假设我们有一个类型T
,它有4个实例方法。
class T {
public:
void member_function_1() { ... }
void member_function_2() { ... }
void member_function_3() { ... }
void member_function_4() { ... }
};
T
副本和实例化100万个T
副本时,这些方法占用的内存量是一样的。
- 访问存储在向量C++中的结构的多态成员
- 如何创建存储指向成员函数的指针的类 (C++)
- 哪些存储了不完整类型的 STL 数据结构可以用作类成员?
- 使用成员函数和存储值定义书籍类
- 指向(数据)成员的指针作为非类型模板参数,例如具有自动存储持续时间/无链接
- 在C++中,如果成员引用在其声明中初始化,为什么需要存储空间?
- 通过放置 new 重用数据成员存储
- 如何将提升正常分发存储为类成员
- C++:将未知类型的对象存储为成员变量的类
- structtm是否将时区信息存储为其数据成员
- 是否值得使用位移在单个字节中存储多个小数据成员?
- 将列表迭代器存储为成员
- 是否有更好的方法来封装成员对象可以访问的共享存储池?
- 流的奇怪问题.不能存储具有特定值的成员变量的对象
- 不从成员函数C 存储返回值认为不良习惯
- 在数据结构中存储成员函数
- 如何通过接口存储成员函数指针
- 存储成员指针与成员值
- 存储成员函数的位置
- GCC如何在内存中存储成员函数