C++ 内存分配/解除分配?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15604411/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:32:43  来源:igfitidea点击:

Memory Allocation/Deallocation?

c++memoryallocationmemory-management

提问by Isaac

I have been looking at memory allocation lately and I am a bit confused about the basics. I haven't been able to wrap my head around the simple stuff. What does it mean to allocate memory? What happens? I would appreciated answers to any of these questions:

我最近一直在研究内存分配,但对基础知识有些困惑。我一直无法理解这些简单的东西。分配内存是什么意思?发生什么了?我希望能回答以下任何问题:

  1. Where is the "memory" that is being allocated?
  2. What is this "memory"? Space in an array? Or something else?
  3. What happens exactly when this "memory" gets allocated?
  4. What happens exactly when the memory gets deallocated?
  5. It would also really help me if someone could answer what malloc does in these C++ lines:

    char* x; 
    x = (char*) malloc (8);
    
  1. 正在分配的“内存”在哪里?
  2. 这个“记忆”是什么?数组中的空间?或者是其他东西?
  3. 当这个“内存”被分配时究竟会发生什么?
  4. 当内存被释放时究竟会发生什么?
  5. 如果有人能回答 malloc 在这些 C++ 行中所做的事情,它也会真正帮助我:

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

Thank you.

谢谢你。

回答by Joseph Mansfield

The Memory Model

记忆模型

The C++ standard has a memory model. It attempts to model the memory in a computer system in a generic way. The standard defines that a byte is a storage unit in the memory model and that memory is made up of bytes (§1.7):

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

The fundamental storage unit in the C++ memory model is the byte. [...] The memory available to a C++ program consists of one or more sequences of contiguous bytes.

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

The Object Model

对象模型

The standard always provides an object model. This specifies that an object is a region of storage (so it is made up of bytes and resides in memory) (§1.8):

该标准始终提供一个对象模型。这指定对象是一个存储区域(因此它由字节组成并驻留在内存中)(第 1.8 节):

The constructs in a C++ program create, destroy, refer to, access, and manipulate objects. An object is a region of storage.

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

So there we go. Memory is where objects are stored. To store an object in memory, the required region of storage must be allocated.

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

Allocation and Deallocation Functions

分配和解除分配函数

The standard provides two implicitly declared global scope allocation functions:

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

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

How these are implemented is not the standard's concern. All that matters is that they should return a pointer to some region of storage with the number of bytes corresponding to the argument passed (§3.7.4.1):

如何实施这些不是标准所关心的。重要的是他们应该返回一个指向某个存储区域的指针,其字节数对应于传递的参数(第 3.7.4.1 节):

The allocation function attempts to allocate the requested amount of storage. If it is successful, it shall return the address of the start of a block of storage whose length in bytes shall be at least as large as the requested size. There are no constraints on the contents of the allocated storage on return from the allocation function.

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

It also defines two corresponding deallocation functions:

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

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

Which are defined to deallocate storage that has previously been allocated (§3.7.4.2):

定义为释放先前分配的存储(第 3.7.4.2 节):

If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage.

如果标准库中释放函数的参数是一个不是空指针值的指针(4.10),释放函数应释放指针引用的存储,使所有指向释放存储任何部分的指针无效.

newand delete

newdelete

Typically, you should not need to use the allocation and deallocation functions directly because they only give you uninitialised memory. Instead, in C++ you should be using newand deleteto dynamically allocate objects. A new-expressionobtains storage for the requested type by using one of the above allocation functions and then initialises that object in some way. For example new int()will allocate space for an intobject and then initialise it to 0. See §5.3.4:

通常,您不需要直接使用分配和释放函数,因为它们只会给您未初始化的内存。相反,在 C++ 中,您应该使用newdelete动态分配对象。甲新表达获得用于通过使用上述分配功能中的一个,然后所请求的类型的存储初始化以某种方式,对象。例如,new int()将为int对象分配空间,然后将其初始化为 0。参见 §5.3.4:

A new-expression obtains storage for the object by calling an allocation function (3.7.4.1).

[...]

A new-expressionthat creates an object of type T initializes that object [...]

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

[...]

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

In the opposite direction, deletewill call the destructor of an object (if any) and then deallocate the storage (§5.3.5):

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

If the value of the operand of the delete-expressionis not a null pointer value, the delete-expressionwill invoke the destructor (if any) for the object or the elements of the array being deleted.

[...]

If the value of the operand of the delete-expressionis not a null pointer value, the delete-expressionwill call a deallocation function (3.7.4.2).

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

[...]

如果删除表达式的操作数的值不是空指针值,则删除表达式将调用释放函数(3.7.4.2)。

Other Allocations

其他分配

However, these are not the only ways that storage is allocated or deallocated. Many constructs of the language implicitly require allocation of storage. For example, giving an object definition, like int a;, also requires storage (§7):

但是,这些并不是分配或取消分配存储的唯一方式。该语言的许多结构都隐含地要求分配存储。例如,给出一个对象定义,如int a;,也需要存储(第 7 节):

A definition causes the appropriate amount of storage to be reserved and any appropriate initialization (8.5) to be done.

定义导致保留适当数量的存储并完成任何适当的初始化(8.5)。

C standard library: mallocand free

C 标准库:mallocfree

In addition, the <cstdlib>header brings in the contents of the stdlib.hC standard library, which includes the mallocand freefunctions. They are also defined, by the C standard, to allocate and deallocate memory, much like the allocation and deallocation functions defined by the C++ standard. Here's the definition of malloc(C99 §7.20.3.3):

此外,<cstdlib>头文件引入了stdlib.hC 标准库的内容,其中包括mallocfree函数。它们也被 C 标准定义为分配和释放内存,很像 C++ 标准定义的分配和释放函数。这是malloc(C99 §7.20.3.3)的定义:

void *malloc(size_t size);
Description
The mallocfunction allocates space for an object whose size is specified by sizeand whose value is indeterminate.
Returns
The mallocfunction returns either a null pointer or a pointer to the allocated space.

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

And the definition of free(C99 §7.20.3.2):

以及free(C99 §7.20.3.2)的定义:

void free(void *ptr);
Description
The freefunction causes the space pointed to by ptrto be deallocated, that is, made available for further allocation. If ptris a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or reallocfunction, or if the space has been deallocated by a call to freeor realloc, the behavior is undefined.

void free(void *ptr);
描述
free函数导致 指向的空间ptr被释放,即,可用于进一步分配。如果ptr是空指针,则不执行任何操作。否则,如果该参数不匹配的指针早些时候返回callocmallocrealloc功能,或如果空间已释放通过调用free或者realloc,该行为是不确定的。

However, there's never a good excuse to be using mallocand freein C++. As described before, C++ has its own alternatives.

然而,在 C++ 中使用malloc和从来没有一个很好的借口free。如前所述,C++ 有自己的替代方案。



Answers to Questions

问题解答

So to answer your questions directly:

所以直接回答你的问题:

  1. Where is the "memory" that is being allocated?

    The C++ standard doesn't care. It simply says that the program has some memory which is made up of bytes. This memory can be allocated.

  2. What is this "memory"? Space in an array? Or something else?

    As far as the standard is concerned, the memory is just a sequence of bytes. This is purposefully very generic, as the standard only tries to modeltypical computer systems. You can, for the most part, think of it as a model of the RAM of your computer.

  3. What happens exactly when this "memory" gets allocated?

    Allocating memory makes some region of storage available for use by the program. Objects are initialized in allocated memory. All you need to know is that you can allocate memory. The actual allocation of physical memory to your process tends to be done by the operating system.

  4. What happens exactly when the memory gets deallocated?

    Deallocating some previously allocated memory causes that memory to be unavailable to the program. It becomes deallocated storage.

  5. It would also really help me if someone could answer what malloc does in these C++ lines:

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

    Here, mallocis simply allocating 8 bytes of memory. The pointer it returns is being cast to a char*and stored in x.

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

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

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

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

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

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

  4. 当内存被释放时究竟会发生什么?

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

  5. 如果有人能回答 malloc 在这些 C++ 行中所做的事情,它也会真正帮助我:

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

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

回答by Mark Ormston

1) Where is the "memory" that is being allocated?

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

This is completely different based on your operating system, programming environment (gcc vs Visual C++ vs Borland C++ vs anything else), computer, available memory, etc. In general, memory is allocated from what is called the heap, region of memory just waiting around for you to use. It will generally use your available RAM. But there are always exceptions. For the most part, so long as it gives us memory, where it comes from isn't a great concern. There are special types of memory, such as virtual memory, which may or may not actually be in RAM at any given time and may get moved off to your hard drive (or similar storage device) if you run out of real memory. A full explanation would be very long!

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

2) What is this "memory"? Space in an array? Or something else?

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

Memory is generally the RAM in your computer. If it is helpful to think of memory as a gigantic "array", it certain operates like one, then think of it as a ton of bytes (8 bit values, much like unsigned charvalues). It starts at an index of 0 at the bottom of memory. Just like before, though, there are tons of exceptions here and some parts of memory may be mapped to hardware, or may not even exist at all!

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

3) What happens exactly when this "memory" gets allocated?

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

At any given time there should be (we really hope!) some of it available for software to allocate. How it gets allocated is highly system dependent. In general, a region of memory is allocated, the allocator marks it as used, and then a pointer is given to you to use that tells the program where in all of your system's memory that memory is located. In your example, the program will find a consecutive block of 8 bytes (char) and return a pointer to where it found that block after it marks it as "in use".

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

4) What happens exactly when the memory gets deallocated?

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

The system marks that memory as available for use again. This is incredibly complicated because this will often cause holes in memory. Allocate 8 bytes then 8 more bytes, then deallocate the first 8 bytes and you've got a hole. There are entire books written on handling deallocation, memory allocation, etc. So hopefully the short answer will be sufficient!

系统将该内存标记为可供再次使用。这非常复杂,因为这通常会导致内存漏洞。分配 8 个字节,然后再分配 8 个字节,然后释放前 8 个字节,你就有了一个空洞。有很多关于处理释放、内存分配等的书籍。所以希望简短的回答就足够了!

5) It would also really help me if someone could answer what malloc does in these C++ lines:

5) 如果有人能回答 malloc 在这些 C++ 行中做了什么,它也会真正帮助我:

REALLY crudely, and assuming it's in a function (by the way, never do this because it doesn't deallocate your memory and causes a memory leak):

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

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

1) This is a pointer reserved in the local stack space. It has not be initialized so it points to whatever that bit of memory had in it.

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

2) It calls malloc with a parameter of 8. The cast just let's C/C++ know you intend for it to be a (char *) because it returns a (void *) meaning it has no type applied. Then the resulting pointer is stored in your x variable.

2) 它使用参数 8 调用 malloc。转换只是让 C/C++ 知道您打算将它设为 (char *),因为它返回 (void *) 意味着它没有应用任何类型。然后结果指针存储在您的 x 变量中。

In very crude x86 32bit assembly, this will look vaguely like

在非常粗糙的 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

The actual allocation is vaguely described in point 3. Malloc usually just calls a system function for this that handles all the rest, and like everything else here, it's wildly different from OS to OS, system to system, etc.

实际分配在第 3 点中进行了模糊的描述。 Malloc 通常只是为此调用一个系统函数来处理所有其余的事情,就像这里的其他一切一样,它从操作系统到操作系统、系统到系统等都大不相同。

回答by Useless

1 . Where is the "memory" that is being allocated?

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

From a language perspective, this isn't specified, and mostly because the fine details often don't matter. Also, the C++standard tends to err on the side of under-specifying hardware details, to minimise unnecessary restrictions (both on the platforms compilers can run on, and on possible optimisations).

从语言的角度来看,这不是指定的,主要是因为细节通常并不重要。此外,该C++标准倾向于在未指定硬件细节方面出错,以最大限度地减少不必要的限制(在编译器可以运行的平台上以及可能的优化上)。

sftrabbit's answer gives a great overview of this end of things (and it's all you really need), but I can give a couple of worked examples in case that helps.

sftrabbit 的回答很好地概述了这一切(这就是你真正需要的),但我可以举几个有用的例子,以防万一。

Example 1:

示例 1:

On a sufficiently old single-user computer (or a sufficiently small embedded one), most of the physical RAM may be directly available to your program. In this scenario, calling mallocor newis essentially internal book-keeping, allowing the runtime library to track which chunks of that RAM are currently in use. You can do this manually, but it gets tedious pretty quickly.

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

Example 2:

示例 2:

On a modern multitasking operating system, the physical RAM is shared with many processes and other tasks including kernel threads. It's also used for disk caching and I/O buffering in the background, and is augmented by the virtual memory subsystem which can swap data to disk (or some other storage device) when they're not being used.

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

In this scenario, calling newmay first check whether your process already has enough space free internally, and request more from the OS if not. Whatever memory is returned may be physical, or it may be virtual (in which case physical RAM may not be assigned to store it until it's actually accessed). You can't even tell the difference, at least without using platform-specific APIs, because the memory hardware and kernel conspire to hide it from you.

在这种情况下,调用new可能首先检查您的进程内部是否已经有足够的可用空间,如果没有,则从操作系统请求更多空间。返回的任何内存可能是物理内存,也可能是虚拟内存(在这种情况下,在实际访问之前可能不会分配物理 RAM 来存储它)。您甚至无法分辨其中的区别,至少在不使用特定于平台的 API 的情况下,因为内存硬件和内核合力将其隐藏起来。

2 . What is this "memory"? Space in an array? Or something else?

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

In example 1, it's something like space in an array: the address returned identifies an addressable chunk of physical RAM. Even here, RAM addresses aren't necessarily flat or contiguous - some addresses may be reserved for ROM, or for I/O ports.

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

In example 2, it's an index into something more virtual: your process' address space. This is an abstraction used to hide the underlying virtual memory details from your process. When you access this address, the memory hardware may directly access some real RAM, or it might need to ask the virtual memory subsystem to provide some.

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

3 . What happens exactly when this "memory" gets allocated?

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

In general, a pointer is returned which you can use to store as many bytes as you asked for. In both cases, mallocor the newoperator will do some housekeeping to track which parts of your process' address space are used and which are free.

通常,会返回一个指针,您可以使用它来存储所需的字节数。在这两种情况下,malloc还是new运营商将进行一些内部管理来跟踪其使用您的进程的地址空间的部分,哪些是免费的。

4 . What happens exactly when the memory gets deallocated?

4 . 当内存被释放时究竟会发生什么?

Again in general, freeor deletewill do some housekeeping so they know that memory is available to be re-allocated.

通常,free或者delete会做一些内务处理,以便他们知道可以重新分配内存。

It would also really help me if someone could answer what malloc does in these C++ lines:

如果有人能回答 malloc 在这些 C++ 行中所做的事情,它也会真正帮助我:

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

It returns a pointer which is either NULL(if it couldn't find the 8 bytes you want), or some non-NULL value.

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

The only things you can usefully say about this non-NULL value are that:

关于这个非 NULL 值,您可以说的唯一有用的是:

  • it's legal (and safe) to access each of those 8 bytes x[0]..x[7],
  • it's illegal (undefined behaviour) to access x[-1]or x[8]or actually anyx[i]unless 0 <= i <= 7
  • it's legal to compareany of x, x+1, ..., x+8(although you can't dereferencethe last of those)
  • if your platform/hardware/whatever have any restrictions on where you can store data in memory, then xmeets them
  • 访问这 8 个字节中的每一个都是合法(且安全的)x[0]..x[7]
  • 这是非法的(未定义的行为)来访问x[-1]x[8]或实际上任何x[i]除非0 <= i <= 7
  • 比较任何一个是合法的x, x+1, ..., x+8(尽管你不能取消引用最后一个)
  • 如果您的平台/硬件/任何对可以在内存中存储数据的位置有任何限制,则x满足它们

回答by user2204592

To allocate memory means to ask the operating system for memory. It means that it is the program itself to ask for "space" in RAM when only when it needs it. For example if you want to use an array but you don't know its size before the program runs, you can do two things: - declare and array[x] with x dediced by you, arbitrary long. For example 100. But what about if your program just needs an array of 20 elements? You are wasting memory for nothing. - then you program can malloc an array of x elements just when it knows the correct size of x. Programs in memory are divided in 4 segments: -stack (needed for call to functions) -code (the bibary executable code) - data (global variables/data) - heap, in this segment you find the allocated memory. When you decide you don't need the allocated memory anymore, you give it back to the operating system.

分配内存意味着向操作系统请求内存。这意味着程序本身仅在需要时才在 RAM 中请求“空间”。例如,如果您想使用一个数组,但在程序运行之前您不知道它的大小,您可以做两件事: - 声明和 array[x] ,其中 x 由您指定,任意长。例如 100。但是如果您的程序只需要一个包含 20 个元素的数组呢?你是在白白浪费内存。- 然后你的程序可以在知道 x 的正确大小时 malloc 一个 x 元素的数组。内存中的程序分为 4 个段:-stack(调用函数所需)-code(二进制可执行代码)-数据(全局变量/数据)-堆,在此段中您可以找到分配的内存。当您决定不再需要分配的内存时,

If you want to alloc and array of 10 integers, you do:

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

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

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

And then you give it back to the os with free(array)

然后你用 free(array) 把它还给操作系统