为什么这个程序不消耗内存?

发布于 2024-11-08 21:15:37 字数 1007 浏览 0 评论 0原文

delete [] 实际上做了什么让我很困扰,所以我只是尝试了一些代码,结果令我震惊

测试 #1:

int main()
{
    int *d;
    while(true)
    {
        d = new int[10];
        delete []d;
    }
}

程序根本不消耗任何内存,正如预期的那样。

测试 #2:

int main()
{
    int *d;
    while(true)
    {
        d = new int[10];
        delete [](d + 5);
    }
}

虽然在每个循环中应该至少保留 20 个字节(对于它在数组开头保留的 5 个整数),但这些字节不会被删除,但该程序也不会消耗任何内存!

测试 #3:

int main()
{
    int *d;
    while(true)
    {
        d = new int[10];
        delete []d;
        *d=1;
    }
}

这正如预期的那样导致了访问冲突(似乎所有内存在 delete []d 之后都被删除了)。

测试#4:

int main()
{
    int *d;
    while(true)
    {
        d = new int[10];
        delete [](d+5);
        *d=1;
    }
}

这是最令人惊奇的,虽然虽然不消耗任何内存,但程序也不会产生任何访问冲突,我只是想知道 *d 在哪里存储它的数据?

(顺便说一句,所有程序都是使用无优化编译的!)

现在的主要问题是:

如果我分配了一个数组并且我已经完成了其中一半的工作,我能不能有机会释放那一半并保留另一半呢?一半?

It's bothering me what delete [] actually does, so I just tried some code and I was shocked with the results

Test #1:

int main()
{
    int *d;
    while(true)
    {
        d = new int[10];
        delete []d;
    }
}

The program doesn't consume any memory at all, as expected.

Test #2:

int main()
{
    int *d;
    while(true)
    {
        d = new int[10];
        delete [](d + 5);
    }
}

Though in every loop there should be at least 20 bytes (for the five ints it reserves at the beginning of array) reserved which are not deleted this program also doesn't consume any memory!

Test #3:

int main()
{
    int *d;
    while(true)
    {
        d = new int[10];
        delete []d;
        *d=1;
    }
}

This one caused access violation as expected (seems all the memory is deleted after delete []d).

Test #4:

int main()
{
    int *d;
    while(true)
    {
        d = new int[10];
        delete [](d+5);
        *d=1;
    }
}

This one was the most amazing, though the while doesn't consume any memory the program doesn't produce any access violations either, I'm just wondering where *d is storing it's data?

(By the way all programs are compiled using no-optimization!)

Now the main question :

What if I allocated an array and I've done working with half of it, can't I by any chance release that half and keep the other half?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

与君绝 2024-11-15 21:15:37

令我烦恼的是删除[]
实际上确实如此

你不应该担心 delete[] 实际做了什么。出于所有意图和目的,它是一个黑匣子,具有有关如何正确使用它的某些规则。您唯一需要担心它实际需要做什么的时候是您正在编写编译器或 C++ 运行时(例如操作系统等)。

关于那些“如何正确使用它的某些规则”,测试#2 和 #4 调用未定义的行为:

ISO C++ 2003 标准 5.3.5 删除 [expr.delete]

1 删除表达式运算符会销毁由 new 表达式创建的最派生对象 (1.8) 或数组。

    delete-expression:
        ::opt delete cast-expression
        ::opt delete [ ] cast-expression

第一个替代方案适用于非数组
对象,第二个是数组。
操作数应具有指针类型,
或具有单个的类类型
转换函数(12.3.2)到
指针类型。结果有类型
无效。

2 如果操作数具有类类型,则
操作数转换为指针类型
通过调用上述
转换函数,以及转换后的
使用操作数代替
其余部分的原始操作数
本节。无论哪种选择,
如果delete操作数的值
是该操作具有的空指针
没有效果。在第一种选择中
(删除对象),的值
删除的操作数应该是一个指针
指向非数组对象或指向的指针
代表基础的子对象 (1.8)
此类对象的类(第 10 条)。
如果不是,则行为未定义。
在第二种选择(删除数组)中,操作数的值
删除应为指针值
这是由先前的数组产生的
新表达。如果没有,则
行为未定义。
[注意:这
意味着语法
删除表达式必须与类型匹配
由 new 分配的对象,而不是
new 表达式的语法。 ]

“未定义的行为”意味着任何事情都可能发生,包括您刚才描述的行为。

测试 #2 和 #4 中的这些表达式违反了 5.3.5/2,并将导致未定义的行为(测试 #3 也会导致未定义的行为,但原因不同)。

d = new int[10];
delete [](d + 5);

delete[] 行违反了 5.3.5/2,因为您传递给 delete[] 的指针值与 new 为您提供的值不同int[]

因此,如果 new int[] 命令为您提供 0xA01D2CE9 并且您将 0xA01D2CE9 + 5 传递给 delete[] ,你不可能推理或预测会发生什么,因为你已经违反了语言的规则。实际发生的情况取决于编译器和/或操作系统如何处理 new[]delete[]。这可能包括从没有发生任何错误到系统完全崩溃,以及介于两者之间的任何情况。

换句话说,只是不要编写诸如 delete [](d + 5); 之类的内容。

it's bothering me what delete []
actually does

You're not supposed to worry about what delete[] actually does. It's for all intents and purposes a black box with certain rules on how to use it properly. The only time you need to worry about what it needs to actually do is if you're writing a compiler or a C++ runtime (e.g. operating systems, etc.)

With respect to those "certain rules on how to use it properly", Test #2 and #4 invokes undefined behavior:

ISO C++ 2003 Standard 5.3.5 Delete [expr.delete]

1 The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression.

    delete-expression:
        ::opt delete cast-expression
        ::opt delete [ ] cast-expression

The first alternative is for non-array
objects, and the second is for arrays.
The operand shall have a pointer type,
or a class type having a single
conversion function (12.3.2) to a
pointer type. The result has type
void.

2 If the operand has a class type, the
operand is converted to a pointer type
by calling the above-mentioned
conversion function, and the converted
operand is used in place of the
original operand for the remainder of
this section. In either alternative,
if the value of the operand of delete
is the null pointer the operation has
no effect. In the first alternative
(delete object), the value of the
operand of delete shall be a pointer
to a non-array object or a pointer to
a sub-object (1.8) representing a base
class of such an object (clause 10).
If not, the behavior is undefined.
In the second alternative (delete array), the value of the operand of
delete shall be the pointer value
which resulted from a previous array
new-expression. If not, the
behavior is undefined.
[Note: this
means that the syntax of the
delete-expression must match the type
of the object allocated by new, not
the syntax of the new-expression. ]

"Undefined Behavior" means that anything can happen, including the behavior you just described.

These expressions that you have in Tests #2 and #4 are in violation of 5.3.5/2 and will cause undefined behavior (Test #3 will also cause undefined behavior, but for a different reason).

d = new int[10];
delete [](d + 5);

The delete[] line violates 5.3.5/2 because pointer value you pass to delete[] wasn't the same value that was given to you from new int[].

So if the new int[] command gives you 0xA01D2CE9 and you pass in 0xA01D2CE9 + 5 to delete[], you cannot possibly reason about or predict what will happen because you have broken the rules of the language. What will actually happen will be dependent on how the compiler and/or the operating system handles new[] and delete[]. That can range from nothing wrong happening to completely crashing your system, and everywhere in between.

In other words, just don't write things like delete [](d + 5);.

鹤仙姿 2024-11-15 21:15:37

当您说“不消耗任何内存”时,您是在谈论“任务管理器”风格的性能监视器内部查看时的情况吗?因为如果是这样,40 字节将不会显示为“内存使用量”...您将必须分配更多内存才能使其显示在大多数标准进程性能监视器中。

When you say "doesn't consume any memory", are you talking about when viewed inside of a "task-manager" style performance monitor? Because if-so, 40-bytes will not show up as "memory usage" ... you're going to have to allocate a lot more memory for it to show up in most standard process performance monitors.

子栖 2024-11-15 21:15:37
delete [](d + 5);

(来自您的测试#2)绝对是您不应该做的事情,如果不是段错误,这会损坏内存。它实际上在我的平台上出现了段错误。

测试的结果将取决于很多因素,其中包括运行这些测试的平台、new/delete 的内部结构等。

delete [](d + 5);

(from your test #2) is definitively something you should not do, this will corrupt the memory if not segfault. It actually segfaults on my platform.

The outcome of your tests will depend on many things, among other things the platform your run these tests on, the internals of new/delete etc.

錯遇了你 2024-11-15 21:15:37
delete [](d + 5);

听起来您希望这仅释放 new int[10] 分配的部分内存。

事实并非如此,它会导致未定义的行为并可能导致任何事情发生。

在某些内存管理器上,如果您要求它们通过传递指针来释放块,如果您不将指针传递到块的开头,那么它们可能会释放包含该指针的整个块你通过了。您的情况很可能会发生这种情况。

另一个考虑因素是 new int[10] 不会初始化分配的内存,因此操作系统只需分配一些地址空间,不需要使用任何物理存储来支持分配。这意味着,即使您在没有任何 delete[] 的情况下在循环中调用 new int[10],您也可能会在许多内存监控工具中看到内存使用量没有上升,甚至高达当您耗尽逻辑bvg地址空间时,new[]抛出std::bad_alloc异常的点。 (一次仅分配 10 个字节可能需要一些时间。)

delete [](d + 5);

It sounds like you are expecting this to free just part of the memory allocated by new int[10].

This is not the case, it causes undefined behavior and could cause anything to happen.

On some memory managers, if you ask them to free a block by passing a pointer, if you don't pass a pointer to the beginning of the block then they may free the entire block that contains the pointer that you pass. This may well be happening in your case.

Another consideration is that new int[10] does not initialize the memory allocated so the operating system can just allocate some address space and doesn't need to back the allocation with any physical storage. This means that even if you call new int[10] in a loop without any delete[] you may see no rising memory usage in many memory monitoring tools, even up to the point when new[] throws a std::bad_alloc exception when you exhaust the logicalbvg address space. (This is likely to take some time just allocating 10 bytes at a time.)

客…行舟 2024-11-15 21:15:37

您是否在发布版本下运行这些测试?您看过生成的汇编指令吗?您如何测量内存消耗?您只分配了 40 个字节,然后立即清除它。

此外,执行诸如 delete [](d + 5) 之类的操作会调用未定义的行为。您需要传入 operator new 返回的指针,以便 delete 正常工作。

Are you running these tests under a release build? Have you looked at the generated assembly instructions? How are you measuring memory consumption? You're ony allocating 40 bytes and then immediately clearing it.

Also, doing something like delete [](d + 5) is invoking undefined behavior. You need to pass in the pointer returned by operator new in order for delete to work correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文