【问题标题】:How to release memory allocated by gcnew?如何释放gcnew分配的内存?
【发布时间】:2015-09-05 22:14:09
【问题描述】:

在任务管理器的帮助下进行了一些测试后,我了解了关于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() 一次,只会给我分配的内存毫无意义。

【问题讨论】:

  • 当初为什么要动态分配?
  • 你到底为什么要使用托管 C++?这就像吃不加糖的蛋糕。
  • 分配给具有垃圾收集系统的进程的内存仅受其性能和良好公民目标的限制。您应该期望它不会不必要地填满您的硬盘。
  • @TomBlodget,但我不需要这个内存,因为这个函数永远不会被调用
  • @DavidHaim C++/CLI 主要用于 C++ 和 .NET 之间的互操作,尝试使用普通 C++ 来实现 - 这就像吃蛋糕加盐 ;-)

标签: memory-management c++-cli


【解决方案1】:

这是gcnew,表示垃圾回收分配。它会被 GC 线程处理和释放

【讨论】:

    【解决方案2】:

    您的函数将内存用于代码和数据。该代码是固定数量的,将在加载库或程序的整个过程中使用。数据仅在函数执行时使用。

    程序使用的数据要么是静态的,要么是动态的。静态数据由编译器布局,基本上等同于代码(除了它可能被标记为不可执行和/或只读以防止意外)。动态数据是临时的,从堆栈或堆(或 CPU 寄存器)分配。

    在经典程序中,栈和堆与栈在一端共享相同的内存地址范围,向堆和另一端的堆增长,尽量不增长到栈中。但是,对于 1TB 量级的现代地址范围,堆通常有很多空间。

    请记住,当程序请求地址范围时,它只是向操作系统发出信号,表明可以将该地址用于数据读取、数据写入和/或代码执行。直到它真正把东西放在那里,系统上没有负载。还请记住,对于虚拟内存系统,进程内存通过优化有效地分配在交换文件/设备(硬盘驱动器)上,特别是使用 RAM 进行缓存、写入时复制和许多其他技术。 (写入内存地址的数据可能永远不会进入交换文件,但这取决于操作系统。)


    您的函数需要的数据是两个变量:tit 是对垃圾收集对象的引用。 i 是一个整数。两者都很小而且寿命很短。您可以将它们视为在堆栈上。当函数返回时,堆栈帧被弹出并且它们的内存被下一个堆栈操作重用。如果您正在查看内存分配,则不会发生变化,因为分配给堆栈的内存量不会改变。

    现在在执行您的函数时,会创建一个新对象,并且它填充数据的方式会占用相当多的内存。您可以考虑在堆中创建该对象。您不需要删除它,因为它是一个垃圾收集对象。当垃圾收集器通过遍历一组根对象中所有可达的对象来运行时,它会发现该对象不可达并将其空间添加到空闲列表中。当需要一个新对象的空间不适合空闲列表上的任何块时,将使用更多的堆地址范围。

    CLR 堆是可压缩的,这意味着它可以移动对象以合并空闲块。使用此功能,它可以将对象移出分配的内存区域并将其返回给操作系统,从而释放交换文件中的空间。

    因此,要看到分配给进程的内存量减少,必须发生三件事:

    1. 已运行垃圾收集以查找无法访问的对象。
    2. 堆已被压缩。
    3. 堆分配已减少。

    在交换文件不能再增长之前,这些东西都不是必需的。显然,该系统是为性能而设计的,并且是为了成为一个好公民,所以它不会走那么远。您可以影响垃圾收集何时运行,但这很少有帮助,通常不会这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-09
      • 1970-01-01
      • 2011-05-13
      • 2015-07-30
      相关资源
      最近更新 更多