【问题标题】:Memory segmentation内存分割
【发布时间】:2012-08-17 16:59:38
【问题描述】:

我在一次采访中被问到这些问题。

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

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 究竟有何不同,以及对象在内存中的行为究竟如何。

【问题讨论】:

  • 在这个上下文中什么是对象表?
  • 我猜这里的对象表是指编译器符号表?
  • 除非你要去编译器团队工作,否则我会问为什么这很重要。编译器将使用基于每个平台定义的最佳解决方案。
  • 我的意思是说show函数将如何调用以及该函数的地址存储在哪里?
  • 我经常接受采访,也接受过采访。一些面试官要抓人什么——那是不公平和错误的。面试的重点不是向正在找工作的人炫耀(那个人很紧张,压力很大)。无论如何,这些公司不值得为之工作。 (这是我的咆哮和我的拙见)

标签: c++ oop class object


【解决方案1】:

代码段与数据段

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

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

而且,代码段通常被加载到只读的内存页面中(VirtualAlloc(PAGE_READONLY))

a(null) vs aa(non-null)

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

a->show() 被翻译成:

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

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

aa->show() 被翻译成:

A_show(aa)

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

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

【讨论】:

  • 面试官对这个答案不满意..我给了他这个答案
  • 感谢详细的回复。
【解决方案2】:

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

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

好吧,我不假装完整。

【讨论】:

  • 好点!这也归结为代码段的只读属性。
【解决方案3】:

我想第二部分是一个有点技巧的问题。你会认为会发生分段错误,但由于A::show 没有引用类的任何数据部分,它将被优化为二进制代码的一部分(几乎就像一个静态方法),你会得到“hellohello” .只需将 printf 更改为 printf("hello %d ", i); 就会出现分段错误。

【讨论】:

    猜你喜欢
    • 2018-11-01
    • 2013-05-13
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    • 1970-01-01
    • 2019-07-15
    • 1970-01-01
    • 2018-03-15
    相关资源
    最近更新 更多