内存分配/释放?

我最近一直在研究内存分配问题,我对基础知识有点困惑。 我一直无法围绕简单的东西包扎头脑。 分配内存意味着什么? 怎么了? 我会很高兴回答以下任何问题:

  • 正在分配的“记忆”在哪里?
  • 这是什么“记忆”? 数组中的空间? 或者是其他东西?
  • 这个“内存”被分配时究竟发生了什么?
  • 当内存被释放时究竟发生了什么?
  • 如果有人能够回答这些C ++代码中malloc的含义,它也会帮助我:

    char* x; 
    x = (char*) malloc (8);
    
  • 谢谢。


    记忆模型

    C ++标准有一个内存模型。 它试图以通用的方式在计算机系统中对内存进行建模。 该标准定义了一个字节是存储器模型中的一个存储单元,该存储器由字节组成(§1.7):

    C ++内存模型中的基本存储单元是字节。 [...] C ++程序可用的内存由一个或多个连续字节序列组成。

    对象模型

    标准总是提供一个对象模型。 这指定对象是一个存储区域(所以它由字节组成并驻留在内存中)(§1.8):

    C ++程序中的结构创建,销毁,引用,访问和操作对象。 一个对象是一个存储区域。

    所以我们走了。 内存是存储对象的地方。 要将对象存储在内存中,必须分配必需的存储区域。

    分配和释放函数

    该标准提供了两个隐式声明的全局范围分配函数:

    void* operator new(std::size_t);
    void* operator new[](std::size_t);
    

    这些如何实施并不是标准的问题。 重要的是,它们应该返回一个指向某个存储区域的指针,其中传递的参数对应的字节数(§3.7.4.1):

    分配函数尝试分配请求的存储量。 如果成功,它应该返回一个存储块的开始地址,这个存储块的长度以字节为单位,应至少与请求的大小一样大。 从分配函数返回时,分配存储的内容没有限制。

    它还定义了两个相应的释放函数:

    void operator delete(void*);
    void operator delete[](void*);
    

    定义哪些是用于释放先前已分配的存储空间(第3.7.4.2节):

    如果在标准库中赋予释放函数的参数是一个不是空指针值(4.10)的指针,解除分配函数应该释放指针引用的存储器,使所有指向解除分配存储器任何部分的指针无效。

    newdelete

    通常,您不应该直接使用分配和释放函数,因为它们只会给您提供未初始化的内存。 相反,在C ++中,您应该使用newdelete来动态分配对象。 新表达式通过使用上述分配函数之一获取请求类型的存储,然后以某种方式初始化该对象。 例如, new int()将为int对象分配空间,然后将其初始化为0.请参阅第5.3.4节:

    新表达式通过调用分配函数(3.7.4.1)获取对象的存储。

    [...]

    一个创建T类型对象的新表达式初始化该对象[...]

    在相反的方向上, delete将调用对象的析构函数(如果有的话),然后释放存储(第5.3.5节):

    如果delete-expression的操作数的值不是空指针值,则delete-expression将调用该对象的析构函数(如果有)或要删除的数组的元素。

    [...]

    如果delete-expression的操作数的值不是空指针值,则delete-expression将调用一个释放函数(3.7.4.2)。

    其他分配

    但是,这不是存储分配或释放的唯一方式。 语言的许多结构隐含地要求分配存储空间。 例如,给出一个对象定义,如int a; ,还需要存储(§7):

    一个定义会导致适当的存储量被保留,并进行任何适当的初始化(8.5)。

    C标准库: mallocfree

    另外, <cstdlib>头文件<cstdlib>stdlib.h C标准库的内容,其中包含mallocfree函数。 它们也被C标准定义为分配和释放内存,就像C ++标准定义的分配和释放函数一样。 以下是malloc的定义(C99§7.20.3.3):

    void *malloc(size_t size);
    描述
    malloc函数为大小由size指定且值不确定的对象分配空间。
    返回
    malloc函数返回空指针或指向分配空间的指针。

    free的定义(C99§7.20.3.2):

    void free(void *ptr);
    描述
    free函数使ptr指向的空间被释放,也就是说,可用于进一步分配。 如果ptr是空指针,则不会发生任何操作。 否则,如果参数与先前由callocmallocrealloc函数返回的指针不匹配,或者如果通过调用freerealloc释放空间,则行为未定义。

    但是,在C ++中使用mallocfree是没有好的借口的。 如前所述,C ++有其自己的选择。


    问题的答案

    所以要直接回答你的问题:

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

    C ++标准不关心。 它只是说程序有一些由字节组成的内存。 该内存可以分配。

  • 这是什么“记忆”? 数组中的空间? 或者是其他东西?

    就标准而言,内存只是一个字节序列。 这是有目的的非常通用的,因为该标准只尝试对典型的计算机系统建模。 大多数情况下,您可以将其视为计算机RAM的模型。

  • 这个“内存”被分配时究竟发生了什么?

    分配内存使某些存储区域可供程序使用。 对象在分配的内存中初始化。 所有你需要知道的是你可以分配内存。 物理内存的实际分配往往是由操作系统完成的。

  • 当内存被释放时究竟发生了什么?

    取消分配先前分配的内存会导致该内存对程序不可用。 它成为释放存储。

  • 如果有人能够回答这些C ++代码中malloc的含义,它也会帮助我:

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

    在这里, malloc只是分配8个字节的内存。 它返回的指针正被转换为char*并存储在x


  • 1)正在分配的“内存”在哪里?

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

    2)这个“记忆”是什么? 数组中的空间? 或者是其他东西?

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

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

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

    4)当内存被释放时究竟发生了什么?

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

    5)如果有人能够回答这些C ++语言中malloc的含义,它也能真正帮助我:

    真的很粗鲁,并假设它在一个函数中(顺便说一句,从不这样做,因为它不会释放你的内存并导致内存泄漏):

    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点中有详细的描述.Marcoc通常只是调用一个系统函数来处理所有其他事情,并且像这里的其他所有内容一样,它与操作系统,操作系统,系统等等有很大不同。


    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将做一些家务管理,以便他们知道内存可以重新分配。

    如果有人能够回答这些C ++代码中malloc的含义,它也会帮助我:

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

    它返回一个指针,它可以是NULL (如果它找不到所需的8个字节),或者是一些非NULL值。

    对这个非NULL值唯一有用的说法是:

  • 访问这8个字节x[0]..x[7]每一个都是合法的(也是安全的),
  • 除非0 <= i <= 7否则访问x[-1]x[8]或实际上任何x[i]都是非法的(未定义行为)
  • 比较x, x+1, ..., x+8任何一个都是合法的(尽管你不能解除其中的最后一个)
  • 如果你的平台/硬件/无论在哪里可以将数据存储在内存中有任何限制,那么x符合它们
  • 链接地址: http://www.djcxy.com/p/15077.html

    上一篇: Memory Allocation/Deallocation?

    下一篇: Why is initialising a matrix whose size is a power of 2 slow?