内存分配/解除分配?

时间:2013-03-24 21:45:43

标签: c++ memory allocation memory-management

我最近一直关注内存分配,而且我对基础知识有点困惑。我无法绕过简单的东西。分配内存意味着什么?怎么了?我很感激这些问题的答案:

  1. 正在分配的“记忆”在哪里?
  2. 这个“记忆”是什么?阵列中的空间?或者是其他东西?
  3. 当这个“记忆”被分配时会发生什么?
  4. 当内存被解除分配时会发生什么?
  5. 如果有人能够回答malloc在这些C ++行中所做的事情,这对我也有帮助:

    char* x; 
    x = (char*) malloc (8);
    
  6. 谢谢。

3 个答案:

答案 0 :(得分:11)

1)正在分配的“记忆”在哪里?

这完全不同,基于您的操作系统,编程环境(gcc vs Visual C ++ vs Borland C ++ vs其他任何东西),计算机,可用内存等。一般来说,内存是从所谓的堆,区域分配的。记忆只是等着你使用。它通常会使用您可用的RAM。但总有例外。在大多数情况下,只要它给了我们记忆,它来自哪里并不是一个很大的问题。存在特殊类型的存储器,例如虚拟存储器,其在任何给定时间实际上可能或可能不在RAM中,并且如果用尽实际存储器,则可能移动到硬盘驱动器(或类似的存储设备)。完整的解释会很长!

2)这个“记忆”是什么?阵列中的空间?或其他什么?

内存通常是计算机中的RAM。如果将内存视为一个巨大的“数组”是有帮助的,那么它肯定会像一个一样运行,然后将其视为一吨字节(8位值,非常类似于unsigned char值)。它从内存底部的索引0开始。就像以前一样,这里有很多例外,内存的某些部分可能映射到硬件,甚至根本不存在!

3)当“内存”被分配时会发生什么?

在任何给定的时间都应该(我们真的希望!)其中一些可供软件分配。如何分配是高度依赖系统的。通常,分配一个内存区域,分配器将其标记为已使用,然后指定给您使用它指示程序在内存所在的所有系统内存中的位置。在您的示例中,程序将找到一个8字节(char)的连续块,并在将其标记为“正在使用”之后返回指向块找到该块的指针。

4)当内存被取消分配时会发生什么?

系统将该内存标记为可再次使用。这非常复杂,因为这通常会在内存中造成漏洞。分配8个字节,然后再分配8个字节,然后解除分配前8个字节,你就有了一个漏洞。有关于处理释放,内存分配等的全书都有。所以希望简短的答案就足够了!

5)如果有人能够回答malloc在这些C ++行中所做的事情,那对我来说也会有所帮助:

非常粗暴,并假设它在一个函数中(顺便说一句,永远不要这样做,因为它不会释放你的内存并导致内存泄漏):

void mysample() {
  char *x; // 1
  x = (char *) malloc(8); // 2
}

1)这是在本地堆栈空间中保留的指针。它没有被初始化,因此它指向内存中的任何内存。

2)它使用参数8调用malloc。演员只是让C / C ++知道你想要它(char *),因为它返回一个(void *)意味着它没有应用任何类型。然后生成的指针存储在x变量中。

在非常粗糙的x86 32位程序集中,这看起来很模糊

PROC mysample:
  ; char *x;
  x = DWord Ptr [ebp - 4]
  enter 4, 0   ; Enter and preserve 4 bytes for use with 

  ; x = (char *) malloc(8);
  push 8       ; We're using 8 for Malloc
  call malloc  ; Call malloc to do it's thing
  sub esp, 4   ; Correct the stack
  mov x, eax   ; Store the return value, which is in EAX, into x

  leave
  ret

在第3点中模糊地描述了实际的分配.Malloc通常只调用一个系统函数来处理所有其余的事情,就像这里的其他所有内容一样,它与操作系统,操作系统,系统等等截然不同。

答案 1 :(得分:7)

  

1。正在分配的“记忆”在哪里?

从语言的角度来看,这没有指定,主要是因为细节通常无关紧要。此外,C++标准往往错误地指定硬件细节,以最小化不必要的限制(平台编译器可以运行,以及可能的优化)。

sftrabbit的回答很好地概述了这一结果(这是你真正需要的),但我可以提供一些有用的例子,以防万一。

示例1:

在足够旧的单用户计算机(或足够小的嵌入式计算机)上,大多数物理RAM可能直接可用于您的程序。在这种情况下,调用mallocnew本质上是内部簿记,允许运行时库跟踪当前正在使用的RAM的哪些块。您可以手动执行此操作,但很快就会变得乏味。

示例2:

在现代多任务操作系统上,物理RAM与许多进程和其他任务共享,包括内核线程。它还用于后台的磁盘缓存和I / O缓冲,并由虚拟内存子系统进行扩充,该子系统可以在不使用时将数据交换到磁盘(或其他存储设备)。

在这种情况下,调用new可能首先检查您的进程是否已在内部有足够的空间,如果没有,则从操作系统请求更多。无论返回什么内存都可以是物理的,或者它可以是虚拟的(在这种情况下,可能不会分配物理RAM来存储它直到它实际被访问)。你甚至无法区分,至少在没有使用特定于平台的API的情况下,因为内存硬件和内核会合谋将它隐藏起来。

  

2。这个“记忆”是什么?阵列中的空间?或其他什么?

在示例1中,它类似于数组中的空格:返回的地址标识可寻址的物理RAM块。即使在这里,RAM地址也不一定是平坦的或连续的 - 某些地址可能被保留用于ROM或I / O端口。

在示例2中,它是一个更虚拟的索引:您的进程的地址空间。这是一个抽象,用于隐藏进程中的底层虚拟内存详细信息。当您访问此地址时,内存硬件可能会直接访问某些实际RAM,或者可能需要请求虚拟内存子系统提供一些内容。

  

3。当这个“记忆”被分配时会发生什么?

通常,会返回一个指针,您可以使用该指针存储所需的字节数。在这两种情况下,mallocnew运算符都会进行一些内务处理,以跟踪流程的地址空间的哪些部分被使用以及哪些部分是免费的。

  

4。当内存被解除分配时会发生什么?

一般来说,freedelete会做一些内务管理,因此他们知道可以重新分配内存。

  

如果有人可以回答malloc在这些C ++行中所做的事情,那对我来说也会有所帮助:

char* x; 
x = (char*) malloc (8);

它返回一个指针NULL(如果它找不到你想要的8个字节)或一些非NULL值。

关于这个非NULL值的唯一有用的事情是:

  • 访问这8个字节x[0]..x[7]
  • 中的每个字段是合法的(并且是安全的)
  • 访问x[-1]x[8]或实际任何 x[i]是非法的(未定义的行为),除非0 <= i <= 7
  • 比较任何x, x+1, ..., x+8都是合法的(尽管你不能取消引用最后一个)
  • 如果您的平台/硬件/对您在内存中存储数据的位置有任何限制,那么x会遇到它们

答案 2 :(得分:3)

分配内存意味着向操作系统询问内存。这意味着程序本身只在需要时才在RAM中询问“空间”。例如,如果要在程序运行之前使用数组但不知道其大小,则可以执行以下两项操作: - 声明和数组[x]用x专用你,任意长。例如100.但是如果你的程序只需要一个包含20个元素的数组呢?你无所畏惧。 - 然后你编程可以在知道正确的x大小时malloc一个x元素的数组。 内存中的程序分为4个部分: -stack(调用函数时需要) -code(bibary可执行代码) - 数据(全局变量/数据) - heap,在这个段中你可以找到分配的内存。 当您决定不再需要分配的内存时,请将其返回给操作系统。

如果要分配10个整数的数组,请执行以下操作:

int * array =(int *)malloc(sizeof(int)* 10)

然后你把它还给了os 自由(数组)