内存分段

时间:2012-08-17 16:59:39

标签: c++ oop class object

我在接受采访时被问到这些问题。

  1. 为什么二进制代码和数据完全分开,为什么他们计划数据段为什么不是代码段内的所有内容?
  2. 2

    class A
    {
    private :
        int i;
    public:
        void show()
        {
            printf("hello");
        }
    };
    int main()
    {
        A* a = NULL; (what happens in object table?)
            A* aa =  new A();  (what happens in object table?)
    
            a->show();
        aa->show();
    
        delete aa;
        return 0;
    }
    

    aa和a的确切区别以及对象在内存中的确切行为。

3 个答案:

答案 0 :(得分:2)

代码段与数据段

代码段是只读的,而数据段是读/写的,如果将这两个部分混合在一起,更新数据同时保持代码安全成为一个挑战:一个例子就像Lol4t0所指出的那样:

  

对于OS内存管理,代码段将被换出   它在文件系统上的原始可执行文件,而数据   被视为更改的段被换出到页面文件。如果你混合它们   在一起,您可能会失去将可执行文件重用为分页文件的优势。

而且,代码段通常会加载到只读(VirtualAlloc(PAGE_READONLY)

的内存页面中

a(null)vs aa(非null)

a和aa本身只是A *类型的堆栈变量,但是指向NULL,而aa指向堆中分配的对象。

a-> show()被翻译成:

A_show(a)
//which is:
A_show(NULL)

因为在show()中没有引用成员变量,所以这应该可以正常工作。

aa> show()被翻译成:

A_show(aa)

这里aa是一个有效的地址,所以即使你在show()中引用成员变量,也可以。

注意与虚拟函数不同,虚函数在运行时解析,因此每个对象需要一个vptr,成员函数只是普通函数,它将 this 作为第一个参数,并在编译时由编译器解析。

答案 1 :(得分:1)

分开代码的另一个原因&数据是内存管理。

当你获得较低的物理内存时,你可以“忘记”代码页,并在需要时从光盘重新读取它。但是你不能对数据做同样的事情。在这种情况下,您应该将页面移动到swap / page文件。现在,如果你有混合代码&数据页面,您必须将它们保存在交换/页面中,因此该策略可以节省资源。

好吧,我不假装完整。

答案 2 :(得分:1)

我猜第二部分是一个棘手的问题。您会认为会出现分段错误,但由于A::show不引用该类的任何数据部分,因此它将被优化为二进制代码的一部分(几乎像静态方法)并且您将获得“你好你好”。只需将printf更改为printf("hello %d ", i);,您就会遇到分段错误。