在任务管理器的帮助下进行了一些测试之后,我理解了gcnew
的一件事 - 即使控制离开函数,为局部变量分配的内存也会重新分配,并且仅在控制重新进入此函数时重新分配 - 所以我在困惑中,如何自己解除记忆。以下是该问题的一些示例:
void Foo(void)
{
System::Text::StringBuilder ^ t = gcnew System::Text::StringBuilder("");
int i = 0;
while(++i < 20000000) t->Append(i);
return;
}
正如我所提到的,变量t
的内存在离开Foo()
之后仍然存在,delete
无效,因为它适用于new
,并且只调用Foo()
一次,只给了我毫无意义的分配内存。
答案 0 :(得分:0)
这是@RequestMapping("XXXX")
public ModelAndView/String handlerMethod(@ModelAttribute("bean") Bean bean) { /* method code here */
}
,这意味着垃圾收集分配。它将由GC线程处理和解除分配
答案 1 :(得分:0)
您的函数使用内存来代码和数据。代码是固定数量,将在加载库或程序的整个过程中使用。数据仅在函数执行时使用。
程序使用的数据是静态的或动态的。静态数据由编译器布局,基本上等同于代码(除了它可能被标记为不可执行和/或只读以防止意外)。动态数据是临时的,并从堆栈或堆(或CPU寄存器)分配。
在一个经典程序中,堆栈和堆共享相同的内存地址范围,堆栈位于一端,向堆增长,另一端堆,尝试不进入堆栈。但是,对于大约1TB的现代地址范围,堆通常具有很大的空间。
请记住,当程序请求地址范围时,它只是向操作系统发出信号,表明可以使用该地址进行数据读取,数据写入和/或代码执行。直到它实际上放在那里,系统没有负载。还要记住虚拟内存系统,进程内存有效地分配在交换文件/设备(硬盘驱动器)上,并进行优化,特别是使用RAM进行缓存,写入时复制和许多其他技术。 (写入内存地址的数据可能永远不会进入交换文件,但这取决于操作系统。)
您的函数所需的数据适用于两个变量:t
和i
。 t
是对垃圾收集对象的引用。 i
是一个整数。两者都很小而且寿命很短。你可以把它们想象成堆栈。当函数返回时,弹出堆栈帧并在下一个堆栈操作中重用它们的内存。如果您正在查看内存分配,则不会发生更改,因为分配给堆栈的内存量不会更改。
现在,在执行函数时,会创建一个新对象,并且它填充数据的方式会占用相当多的内存。您可以考虑在堆中创建该对象。您不需要删除它,因为它是垃圾收集对象。当垃圾收集器通过遍历从一组根对象可到达的所有对象来运行时,它将发现该对象不可访问并将其空间添加到空闲列表。当需要一个不适合空闲列表中任何块的新对象的空间时,将使用更多的堆地址范围。
CLR堆是可压缩的,这意味着它可以移动对象以便合并空闲块。使用此功能,它可以将对象移出已分配内存的区域并将其返回给操作系统,从而释放交换文件中的空间。
因此,要看到分配给流程的内存量减少,有三件事情要发生:
在交换文件不再增长之前,这些事情都不是必需的。显然,该系统是为性能而设计的,并且是一个好公民所以它不会那么做。您可以影响垃圾收集运行的时间,但这种情况很少有用,通常无法完成。