【问题标题】:Memory allocation for C programC程序的内存分配
【发布时间】:2015-12-28 03:23:11
【问题描述】:

计划

#include<stdio.h>
int a=10;
void main()
{
    int i=0;
    printf("global = %p, local = %p\n",&a,&i);
    main();
}

输出

mohanraj@ltsp63:~/Advanced_Unix/Chapter7$ ./a.out
global = 0x804a014, local = 0xbfff983c
global = 0x804a014, local = 0xbfff980c
.
.
.
global = 0x804a014, local = 0xbf7fac9c
global = 0x804a014, local = 0xbf7fac6c
global = 0x804a014, local = 0xbf7fac3c
Segmentation fault (core dumped)
mohanraj@ltsp63:~/Advanced_Unix/Chapter7$

上述程序出现分段错误错误。因为, main 递归地调用自己。以下是回忆 分配给 C 程序。

内存分配

          __________________                        __________________  
          |                |                        |                | 
          |      stack     |                        |     Main       |
          |  ↓             |                        |----------------|
          ------------------                        |     Main       | 
          |                |                        |----------------|
          |   <Un Allocated|                        |     Main       |
          |       space>   |                        |----------------|
          ------------------                        |     Main       |
          |                |                        |----------------|
          |    ↑           |                        |     Main       |
          |       Heap     |                        |----------------|
          |                |                        |     Main       |
          |                |                        |----------------|
          __________________                        |////////////////| ---> Collision occurs. So, Segmentation fault Occurs.  
          |                |                        |________________|
          |       data     |                        |       data     |
          __________________                        |________________|
          |       text     |                        |       text     |
          __________________                        |________________|
               Figure(a)                               Figure(b)

所以,我希望如图(b)所示,主要调用递归。如果它到达数据段,就会发生冲突。 如果发生,则没有更多空间可分配给 main 函数。因此,它会出现分段错误错误。所以我用上面的程序做实验。 在该程序中,全局变量“a”的地址是“0x804a014”。每次调用 main 时,都会声明局部变量“i”。所以我 预计,在分段错误之前,i 的地址几乎是“a”的地址。但是,这两个地址是非常不同的。那么这里发生了什么。

为什么segment fault错误时'a'和'i'的地址不在同一范围内。那么,如何交叉检查是否 main 达到堆栈大小并溢出?

【问题讨论】:

  • 暂停程序,看看/proc/pid/maps——里面还有其他东西,比如库。另外,堆栈大小有一个实际限制(ulimit)
  • 可以打印库中对象的地址吗?说,&stdin?还是标准输入?
  • @mohan 您的堆栈大小可能受到ulimit 的限制,即(通常)8MB。即使在 32 位系统上,在这种情况下,您也永远不会让堆栈与数据段重叠;即使他们之间没有一堆图书馆。我试图引导您了解真实流程的地址映射与您展示的简单流程不同。
  • 尝试类似“ulimit -s 65000000 ; ./a.out”,它会持续更长时间。
  • @TobySpeight:C++ 中明确禁止调用 main 3.6.1 Main 函数 [basic.start.main] §3:函数 main 不得在程序中使用 ,但我在 C 规范中找不到等效项,所以看起来应该允许它 - 即使非常罕见......

标签: c linux unix memory


【解决方案1】:

您所拥有的记忆模型过于简单化了,仅在开始向学生教授记忆的基础知识时才有用,以免一开始就被细节压倒。就像我们从添加自然数开始数学教育一样。这是一个很好的基础,但如果你仅仅用它来理解现实,它不会让你走得太远。

此模型至少在 25 到 30 年内都不是准确的,并且不能用于对实际程序行为进行预测。堆和栈(共享库、大型 malloc、文件的 mmap 等)之间可能有数十个(如果不是数千个)其他内存映射。 “堆”的概念是有很大问题的,因为它通常不会比操作系统事先不知道的地址空间中任何位置的匿名内存的所有动态分配的总和多多少。

您的示例中发生的情况是您遇到了堆栈资源限制(请参阅ulimit -s)。

【讨论】:

    【解决方案2】:

    您的架构是概念模型或可能的实现。但是例如,一个多线程程序每个线程有一个堆栈和一个堆,这并不适合您的简化模式。

    所需要的只是系统允许递归,这意味着函数的每次新调用都会获得局部变量的私有副本。剩下的就是依赖于实现了。

    最近系统使用页分配,一个进程一般会得到一组页段,但它们不一定是连续的,它们之间可以有空洞,任何访问都会得到一个SIGSEGV(段违规)

    TL/DR:您的程序将更有可能获得 SIGSEGV 信号,而不是动态变量的地址到达静态变量的地址 - 您应该找到一个旧的 MS/DOS 框来表现这种行为...

    【讨论】:

      【解决方案3】:

      当你写变量“i”被声明时,你写的是正确的,但变量没有声明为全局a

      i是栈分配的,栈有自己的大小。

      ulimit 可以更改该限制。

      你想看到的,全局变量和局部变量的地址分配之间的冲突是不可能的。

      【讨论】:

        【解决方案4】:

        'a' 是一个全局变量,它不会在堆栈中。这将在数​​据部分 - 即初始化 bss

        'i' 是一个局部变量,将存储在堆栈中。

        这些是完全不同的部分,因此存在差异。

        请参考Global memory management in C++ in stack or heap?

        【讨论】:

          猜你喜欢
          • 2016-07-06
          • 1970-01-01
          • 2013-10-15
          • 1970-01-01
          • 2011-11-02
          • 1970-01-01
          • 2016-02-10
          • 2010-09-13
          • 1970-01-01
          相关资源
          最近更新 更多