【问题标题】:Dynamic Memory Allocation Functions- Malloc and Free动态内存分配函数 - Malloc 和 Free
【发布时间】:2012-04-29 03:57:47
【问题描述】:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *p;
p = (char *)malloc(4*sizeof(char));
strcpy(p, "abcdabcd");
printf("%s\n", p);
free(p);
printf("%s\n", p);
return 0;
}

我尝试在 Ubuntu 上运行上述代码。这里我从 malloc 分配 4 个字节的内存。然后我尝试将 8 个字节复制到 malloc 分配的内存中。我没有收到任何警告或错误。我尝试释放内存块并尝试使用被释放的相同内存,但再次没有问题。它打印了正确的字符串。有人可以解释一下这种行为吗?

【问题讨论】:

  • 基本上它的 C 和它由你来执行这些事情。因为 C 非常强调性能,所以不会浪费 CPU 时间来为您执行它。
  • 大多数时候 malloc 分配的内存比你指定的多。我想这就是你的程序有效的原因。
  • 物理内存通常存在于 4kb 页面中,因此可能 malloc 实现会考虑这一点并在您的情况下分配 1 个页面。
  • @strkol,请提供您的断言的来源。
  • @YoussefG.,编译程序并对其进行 strace,您会发现以下内容:mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76e0000。 malloc() 分配了 4096 个字节...

标签: c


【解决方案1】:

无法对行为进行有意义的解释。您的程序表现出 undefined 行为,这意味着任何事情都可能发生。 “任何东西”还包括您在实验中观察到的行为,即“打印正确的字符串”。

今天它“打印了正确的字符串”。明天它可能会崩溃。后天它可能会格式化您的硬盘。在未定义行为的概念下,这是完全允许的。

【讨论】:

    【解决方案2】:

    显然正确的操作属于[未定义的行为]类。

    【讨论】:

      【解决方案3】:

      当程序启动时,它可以通过操作系统访问虚拟内存。通常虚拟页面有一些最小尺寸(比如 4 kb),这是处理它们的最小尺寸。

      因此,您使用低于此页面大小的 malloc 请求内存,并且整个块都可用。 此块的某些/无/全部可能被其他程序使用。但它在技术上仍然存在:

      1 byte | 1 byte | 1 byte | 1 byte | more memory you don't have....
       ^ char p points here
      

      然后您开始将字符串复制到内存中从 p 开始。所以你得到:

      a | b | c | d | the rest of the chars start dumping into somebody elses space!
      

      这种重叠是未定义的。换句话说,我们可能有未使用的内存,所以今天一切正常。明天,该物理内存空间由操作系统持有,我们无法覆盖它。第二天,我们打破了一些其他的程序。之后的第二天,我们就出现了故障。

      正如其他人所指出的,C 不会照顾你。

      【讨论】:

        【解决方案4】:

        C 语言不保证任何内存检查。基本上,如果您写入不属于您的内存(例如,您写入的内存超出了数组的范围)或者您从不属于您的内存中读取(例如,您通过释放它来读取您放弃的内存) ) 不知道会发生什么。

        但是,操作系统可能会也可能不会阻止您执行上述任何一项操作。通常,如果发生这种情况,您会收到“总线错误”或"Segmentation Fault"。但是,也不能保证这两种情况都会发生。

        最好的办法是防御性地编写代码。跟踪您的数组的长度,然后断言或以其他方式检查当您复制到数组时不会超过数组大小。

        您可以做的另一件事是调试。 Valgrind 是一种非常有效的工具,可以解决您所描述的问题。它可以指示您读取或写入尚未 malloc 的内存的两种情况。它还可以识别泄漏,例如当您 malloc 内存然后忘记释放它时。

        【讨论】:

          【解决方案5】:

          我相信它会沿着块对齐分配,这就是为什么它在这种情况下给你一些神奇的额外内存。尝试将其提高到更大的字节倍数(例如 16,64 等,它应该更准确,如果超出它可能会出现段错误)。但请记住,如果 malloc 块之后的内存也是程序内存空间的一部分……那么您也不会遇到段错误。

          一般来说,只要你留在你的程序内存段中,你就可以愉快地读/写你想要的一切(当然后果自负:D)。

          如果你真的想检查你的程序,用/in 'valgrind'运行它

          【讨论】:

            【解决方案6】:

            所有说你调用了未定义行为的人都是正确的。

            它看起来正常工作的原因可能是您平台上堆管理器的特定实现的副作用。例如,许多内存管理器将分配四舍五入到一些方便的大小,最小的大小通常是 8 或 16 字节。您应该从不依赖此类实施细节。

            有些平台有工具可以在您开发程序时尝试捕捉这些类型的假设。

            【讨论】:

              【解决方案7】:

              正如所有其他人所说,您的代码会导致 undefined 行为(任何事情都可能发生)。

              您的堆内存分配器 (malloc) 不对存储在 释放后的区域

              了解 malloc 的职责将帮助您解释为什么会看到结果,为什么它不正确的编程实践以及为什么它不能一直工作。

              Malloc 是 glibc 中的堆内存分配器(_int_malloc 和 _int_free)。您可以在此处查看其代码 [http://code.woboq.org/userspace/glibc/malloc/malloc.c.html#_int_malloc]

              有人可以解释一下这种行为吗?

              一个有趣的例子可以帮助你快速澄清你的问题。

              假设您从汽车旅馆 (sbrk(2)) 租了一个房间 (memory),但没有任何房间的钥匙 (memory)! .
              你去找接待员 (ma​​lloc) 并要一个房间 (memory),她给你一个有空的房间,你就占了房间 (memory)并使用它。
              你已经完成了它,现在向她保证你不会再次使用它(释放)。她在她的书中做了一个条目,您的房间(记忆)是免费的,可以分配给其他人。把房间给别人或不给别人,完全是她的心愿。
              过了一段时间你又来看看你的房间(接待员没有检查你),如果你发现没有人使用房间,你很幸运(它看起来和你离开时一样乱!)

              接待员(malloc)的工作是尽快给你分配一个房间(内存),相信你离开后会遵守诺言(免费)。她的工作不是阻止你使用任何房间(内存)!

              如果你访问一个你不被允许进入的地方(只读区域),所有者(内核)会变得愤怒(例外)。

              我是新手,我不确定这样回答是否合适。让我知道我是否错了 我强烈建议你通过 malloc

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-07-16
                • 1970-01-01
                • 2022-11-10
                • 2021-03-02
                • 2020-11-23
                • 2010-12-16
                • 2013-11-20
                • 1970-01-01
                相关资源
                最近更新 更多