C++ 操作系统是否知道程序在操作系统提供的内存块中删除或释放了任何内存位置?

C++ 操作系统是否知道程序在操作系统提供的内存块中删除或释放了任何内存位置?,c++,operating-system,window,C++,Operating System,Window,最近,我发现了一些有趣的代码 int main() { int* a = new int; *a = 5; int* b = a; delete a; std::cout << *b << std::endl; } intmain() { int*a=新的int; *a=5; int*b=a; 删除一条; STD::CUT首先,我将从C++的角度回答: 操作系统是否知道程序在操作系统提供的内存块中删除或释放了任何内存位置 操

最近,我发现了一些有趣的代码

int main()
{
    int* a = new int;
    *a = 5;

    int* b = a;

    delete a;

    std::cout << *b << std::endl;
}
intmain()
{
int*a=新的int;
*a=5;
int*b=a;
删除一条;

STD::CUT

首先,我将从C++的角度回答:

操作系统是否知道程序在操作系统提供的内存块中删除或释放了任何内存位置

操作系统能知道程序是否在内存块中分配和释放内存吗

我想知道程序什么时候把内存块还给操作系统

这些不是由C++语言指定的。< /P> 大多数情况下,它工作得很好

没有。一个行为未定义的程序不会“很好地工作”,即使它看起来很好地工作

它打印“5”

这是一种可能的行为。当程序的行为未定义时,这是不能保证的

我了解到这是因为程序正在从操作系统访问已经分配的内存块(可能是第页),它不会给出任何异常

它不会给出任何异常,因为它不能保证这样做,因为程序的行为是未定义的


在这里,我将从操作系统的角度介绍一些内容。不幸的是,我对Windows的具体知识并不深入,因此这是一般性的,而不是具体的

还是程序管理可用内存列表

在实践中,必须管理描述所有分配器的数据结构。无论是直接的语言实现(编译器/运行时库),还是操作系统在不同的系统中有所不同。我听说在Windows上,调试版本和发布版本之间也可能有所不同

(若程序对此进行管理,为什么在访问释放位置(b)时不给出任何异常?)

无论该列表是否由语言实现(编译器/运行时库)管理,或通过操作系统,这样的检查没有完成,因为每次访问内存时检查这样的列表在处理器时间方面会非常昂贵。实现这种语言或操作系统的人可能认为,将每个程序的速度降低一个重要因素并不值得增加安全性

操作系统通常在“页面”中处理虚拟内存这些都是大的块。当访问未映射到内存中的页面时,操作系统通常会在该点检查程序是否应该访问它。如果没有,则程序通常会出于安全考虑终止,因为它被认为行为不稳定。这些页面是比单个页面更粗糙的内存划分双重分配

我想知道程序什么时候把内存块还给操作系统


不同的实现和情况也会有所不同。非常典型的是,内存根本不会返回给操作系统,而是用于以后的分配。所谓“全部”,我的意思是进程会保留内存直到终止。

释放动态分配内存的函数(例如
操作符delete()
)不需要立即将其释放到主机系统。实际上,他们通常不需要,因为程序员经常反复释放内存,然后再重新分配内存。向操作系统释放内存并再次请求类似的块的往返过程在计算上通常比标准库函数跟踪和重新分配内存的计算成本更高欧盟秘书处先前已“释放”块而不与操作系统交互。不同的标准库,甚至是标准库的版本,在这方面的行为不同。根据标准,您的代码具有未定义的行为-本质上是因为您的程序假定它可以在释放后访问动态分配的内存。输出为
5
完全可以接受(例如,因为内存实际上还没有释放到操作系统中)。并且
42
的输出是可以接受的(例如,因为操作系统只是检索一个随机值)。重新格式化硬盘是可以接受的(例如,因为您的标准库覆盖了物理内存的一些关键区域)。这就是未定义行为的本质。“向操作系统释放内存的往返”可能意味着向操作系统提供一页内存,然后(响应动态分配内存的后续语句)请求另一页内存。这是否真的意味着这取决于编译器的实现、标准库的编码方式、操作系统如何管理内存,以及一大堆其他事情。@SungJinKang当你调用
delete
时,它只是告诉代码在某个时候将内存释放回操作系统,你没有任何问题想法何时(通常是在不久的将来)。因此,当然,如果您在之后立即打印,并且内存尚未释放,您可能会打印
5
。但是,您也可以打印一些其他值(如果该内存被调用
std::cout
)。另一方面,如果内存已经释放到操作系统,您将尝试访问非您的内存,因此操作系统将引发异常,您的代码将“崩溃”。@SungJinKang我不会说我确切知道这是如何发生的,我会假设您请求内存(通过参考虚拟内存地址),然后有硬件将虚拟地址解析为实际地址,我猜这就是检测到错误的地方。然后,这可能会向操作系统发出信号,操作系统会反过来引发代码中的异常(即,在Linux下发送SIGSEGV,在Windows下发送类似的东西,但带有这些可怕的句柄).但正如我所说,我不确定这是否就是事情的发展方向。