C++ 为什么程序分配的内存不';不减少?

C++ 为什么程序分配的内存不';不减少?,c++,memory-management,C++,Memory Management,有一条规则告诉我们,局部变量在调用函数结束后被删除 我尝试调用该函数(在C++中) 并研究了在创建数组x时,程序分配的内存增加了一些KBytes。然而,在调用函数结束后,内存并没有减少。另外,函数delete给出运行时错误 那么,为什么程序分配的内存在结束调用函数后不会减少呢?是否有任何方法可以删除上述局部变量?对于任何大量内存分配,一定要使用new和delete;比方说,对于超过1Kb或可能使用超过1Kb内存的任何对象,如果要将其放入一个类中,则可能需要使用一个局部静态变量来计算实例数(int

有一条规则告诉我们,
局部变量
在调用函数结束后被删除

我尝试调用该函数(在C++中)

并研究了在创建数组
x
时,程序分配的内存增加了一些
KBytes
。然而,在调用函数结束后,内存并没有减少。另外,函数
delete
给出运行时错误


那么,为什么程序分配的内存在结束调用函数后不会减少呢?是否有任何方法可以删除上述局部变量?

对于任何大量内存分配,一定要使用new和delete;比方说,对于超过1Kb或可能使用超过1Kb内存的任何对象,如果要将其放入一个类中,则可能需要使用一个局部静态变量来计算实例数(int my_class::static_variable;)给类的每个实例一个唯一的id和一个内存分配标志,这样您就可以跟踪谁得到了内存分配,谁没有,谁的内存被释放——然后您将在任务管理器中观察内存消耗的预期增加和减少;我离题了。与磁盘驱动器虚拟内存分配无关


总的来说,当涉及到内存管理时,使用这样一个静态大小的数组是非常不负责任的,即使它本身保证不会出现内存泄漏,因为很可能您不需要立即整体分配所有内存,除非您跳入一个循环,循环遍历数组中的每个条目。

令人惊讶的是,由于您没有初始化(或触摸)数组,内存使用率会上升。另一方面,任务管理器中的内存使用率没有下降也就不足为奇了。不过,这没什么好担心的

为什么会这样

当您像这样声明一个数组时,它具有自动存储持续时间。这意味着为它分配了堆栈上的空间(正式地,C++语言不知道“堆栈”),但这就是所有实现(至少我所听到的所有实现都是这样工作的)。 在堆栈上分配空间仅仅是指针减量某个值。只要您不尝试读取或写入指向的内存,您几乎可以对指针执行任何操作,而不会发生任何事情(当然,会发生一些事情,但不会发生引人注目的事情)

在较低的级别上,内存是以页(通常为4千字节)的形式管理的,这些页以某种不透明的方式将一系列具有某些访问权限的虚拟地址映射到物理RAM。操作系统确保您永远不会知道这一点。现在,操作系统故意将堆栈最后一页后面的页设置为无效访问模式,因此每当您尝试从该页读取或写入值时,都会生成错误1。当这种情况发生时,操作系统将检查堆栈的最大大小是否已超过(在这种情况下,程序将终止)。如果不是这样,操作系统将提交一个新页面,将其添加到您的工作集中,并让您的程序继续

这样做的好处是,可以为每个线程提供大量线程和非常大的理论堆栈大小,但您只需为使用的线程付费

现在,当您分配一个10万个
double
s的数组时,发生的情况是堆栈指针向下移动800000字节(假设
double
的“通常”大小为8字节)。如果您也初始化了该数组,或者如果您在该数组之后触碰了您声明的任何其他变量,则会出现所述页面错误,操作系统将被启动并分配堆栈空间。Process Explorer将显示它

一旦提交,它将不再消失2,任务管理器将继续显示它。但是,一旦函数返回,堆栈指针就会弹回到它之前所在的位置,因此可以循环使用该内存

请注意,堆栈通常不能无限增长(通常,默认情况下,它被限制为一兆字节左右)。因此,分配具有静态存储持续时间的大型阵列通常不是一个好主意


1在Windows下,有一个专门的术语:保护页

2原则上可以,但操作系统无法简单地判断何时可以安全地丢弃页面,而不需要编译器插入额外的系统调用,并且简单地保留页面并在最坏的情况下将其交换,这样做很好,而且容易得多。

您如何衡量内存使用?您的衡量可能有缺陷<代码>x在堆栈上分配。在任务管理器->进程中,尝试使用new分配内存。那么使用delete就可以了。你需要仔细阅读虚拟内存和物理内存之间的区别。任务管理器很可能向您显示了物理内存消耗(许多度量之一)。在不了解虚拟内存的情况下,我能给您的唯一答案是,没有内存泄漏,您可以放心,堆栈分配可以按照广告的方式工作。
void DoIt()
{   
    double x[100000];
}