线程模型和类实例内存管理

时间:2014-07-21 20:52:09

标签: c++ multithreading

假设我们在堆栈中创建了一个类的实例。据我所知,编译器根据该实例中的字段类型和数量为其提供特定数量的内存。但我对实例方法感到困惑。我假设他们有自己的堆栈框架。

我不明白:

  1. 实例方法的堆栈框架位于何处?它们是否位于实例堆栈框架内部或存储在其他位置?
  2. 是否只为该类的许多实例创建了一个实例方法堆栈框架
  3. 如果是这样,那么如果同一个类的两个对象同时从不同的线程调用相同的函数呢?

4 个答案:

答案 0 :(得分:9)

与普通函数一样,C ++中有多个与成员函数关联的内存块。首先,有组成成员函数的实际汇编指令,通常放入代码段,不应该有任何问题。其次,每次调用该成员函数时,都会为该调用内部的所有局部变量("自动对象")保留额外的堆栈空间,该调用将在调用返回时清除。我应该特别指出函数没有为它们的堆栈空间设置一些固定的预分配内存 - 例如,如果一个函数是递归的,那么你可能同时有多个堆栈帧对该函数有效。相反,需要尽可能多的堆栈帧。

在C ++中声明类类型的局部变量时,只能获取对象本身的内存。没有分配额外的内存来保存该对象的成员函数 - 如上所述,成员函数内存要么放在数据段中,要么在调用成员函数时根据需要进行分配。具体来说,如果在已声明的对象上调用成员函数,则程序将为该成员函数分配新的堆栈帧,调用该函数,并在函数返回时清理内存。没有额外的"溢价"支付会员职能;它们实际上并不影响对象的大小(尽管在您的类中有一个或多个虚函数可能会增加一次性成本到对象的大小)。

当然,这完全取决于实现;一个实现原则上可以分配额外的空间来存储对象内的成员函数,但据我所知,没有标准的C ++实现可以做到这一点。 (如果您知道vtable是什么,该对象可能有一个vtable指针,但不是所有vtable条目。)

希望这有帮助!

答案 1 :(得分:5)

  

1。实例方法的堆栈框架位于何处?它们是否位于实例堆栈框架内部或存储在其他位置?

没有像实例堆栈框架这样的东西。堆栈帧是在实际执行线程的调用堆栈中创建的。

  

2. 是否只为该类的许多实例创建了一个实例方法堆栈框架

请参阅我对1.的回答。每个线程有不同的调用堆栈,是的。

  

3。如果是这样,那么如果同一个类的两个对象同时从不同的线程调用相同的函数会怎样呢?

如前所述,为每个线程创建了不同的堆栈帧。每个实例没有任何调用堆栈帧。它只是不同的隐式传递的this指针,用于区分所访问的实例。

答案 2 :(得分:4)

方法本质上是操作码(机器操作)的“块”,位于可执行映像的(只读)代码段中。

因此,方法与堆栈无关(就它们所在的内存而言)。

然而,只要他们对局部变量执行操作,他们就会访问堆栈。

类的实例不“包含”类方法,而只包含类属性(在类中定义的变量),并且可能是指向类的V-Table的指针(如果定义了一个)或者类或其中一个基类中的更多虚函数。


只要一个方法对非静态局部变量或非静态成员变量进行操作,它就是线程安全的,因为每次调用该方法时这些变量都会在堆栈中分配,并且每个线程都有自己的堆栈(在整个堆栈中它自己的独立区域,更准确)。

一旦方法对未在堆栈中分配的变量(静态局部变量,静态成员变量,静态全局变量或非静态全局变量)进行操作,它就变得线程不安全,必须这样处理(通常使用适当的操作系统资源,如信号量,互斥量等)。

答案 3 :(得分:0)

另外,请记住,内联函数/方法调用可能根本不会创建堆栈帧。

che编译器可以内联函数调用进行优化。