垃圾收集可以与显式内存管理共存吗?

时间:2008-10-25 12:01:15

标签: language-agnostic garbage-collection computer-science theory

例如,假设一个是在C#4中包含一个'delete'关键字。是否可以保证你永远不会有野性指针,但仍然能够依赖垃圾收集器,因为参考基于系统?

我能看到它可能发生的唯一方法是,如果不是对内存位置的引用,那么引用将是指向实际对象的指针表的索引。但是,我确信会有一些情况会破坏,并且有可能打破类型安全/悬挂指针。

编辑:我不是在谈论.net。我只是以C#为例。

9 个答案:

答案 0 :(得分:3)

你可以 - 有点:让你的物品一次性使用,然后自行处理。

手动删除不太可能提高托管环境中的内存性能。它可能对非托管资源有所帮助,处理的是什么。

我宁愿实现和使用Disposable对象变得更容易。我没有一致的,完整的想法,这应该是什么样子,但管理非托管资源是.NET下的冗长的痛苦。


实施删除的想法: delete标记用于手动删除的对象。在下一个垃圾收集周期中,该对象将被删除,并且对它的所有引用都将设置为null。

起初听起来很酷(至少对我而言),但我怀疑它会有用。 这也不是特别安全 - 例如另一个线程可能正在忙于执行该对象的成员方法,这样的方法需要抛出,例如访问对象数据时。

答案 1 :(得分:2)

使用垃圾收集,只要您有对象的引用引用,它就会保持活动状态。手动删除时,您无法保证。

示例(伪代码):

obj1 = new instance;
obj2 = obj1;

// 

delete obj2;
// obj1 now references the twilightzone.

简而言之,将手动内存管理与垃圾回收相结合,会破坏GC的目的。此外,为什么要这么麻烦?如果你真的想要控制,使用C ++而不是C#。 ; - 。)

答案 2 :(得分:1)

你可以得到的最好的是分成两个“半球”,其中一个半球被管理,并且可以保证没有悬空指针。另一个半球有明确的内存管理,不提供任何保证。这两个可以共存,但不,你不能给第二个半球提供强有力的保证。你所能做的就是跟踪所有指针。如果删除了一个,那么指向同一实例的所有其他指针都可以设置为零。不用说,这是非常昂贵的。你的表会有所帮助,但会引入其他费用(双重间接)。

答案 3 :(得分:0)

Chris Sells也在.NET Rocks上讨论了这个问题。我认为这是在他第一次出现时,但这个话题可能会在以后的采访中重新审视。

http://www.dotnetrocks.com/default.aspx?showNum=10

答案 4 :(得分:0)

我的第一反应是:为什么不呢?我无法想象你想做的事情就像隐藏在堆上的未引用的块以便稍后再找到它一样。好像指向堆的四字节指针太多而无法维护以跟踪此块。

所以问题不在于分配未引用的内存,而是故意处置内存仍在引用中。由于垃圾收集执行在某些时候标记内存空闲的功能,似乎我们应该能够调用另一个指令序列来处理这个特定的内存块。

然而,问题在于:

String s = "Here is a string."; 
String t = s;
String u = s;
junk( s );

tu指向什么?在严格的参考系统中,tu应为null。这意味着您不仅需要引用计数,还可以跟踪

但是,我可以看到您应该在您的代码中使用s。因此junk可以将引用设置为null,并使用某种优先级代码将其传递给清理程序。 gc可以在有限的运行中激活,只有在无法访问时才释放内存。所以我们不能明确地释放任何某人编码以某种方式再次使用的东西。 但是如果s是唯一的引用,那么该块将被释放。

所以,我认为它只适用于有限的遵守显式方面。

答案 5 :(得分:0)

可以并且已经实现了非托管语言,例如C ++。基本上,您实现或使用现有的垃圾收集器:当您需要手动内存管理时,您可以正常调用new和delete,当您想要垃圾收集时,可以调用GC_MALLOC或任何函数或宏用于垃圾回收器。

有关示例,请参阅http://www.hpl.hp.com/personal/Hans_Boehm/gc/

由于您使用C#作为示例,可能您只考虑使用托管语言实现手动内存管理,但这是为了向您显示反向可能。

答案 6 :(得分:0)

如果对象引用上的delete的语义会使引用该对象的所有其他引用都为null,那么你可以使用2个间接级别(比你提示多1个)。虽然请注意,虽然底层对象将被销毁,但必须在堆上保留固定数量的信息(足以容纳引用)。

用户使用的所有引用都会将隐藏引用(可能存在于堆中)引用到真实对象。当对对象执行某些操作时(例如调用方法或依赖于它的标识,如使用==运算符),程序员使用的引用将取消引用它指向的隐藏引用。删除对象时,实际对象将从堆中删除,隐藏引用将设置为null。因此,引用程序员会将evaluate视为null。

清除这些隐藏的引用将是GC的工作。

答案 7 :(得分:0)

这对于长寿命对象的情况会有所帮助。当对象短时间使用并快速取消引用时,垃圾收集效果很好。问题是当一些物体存在很长时间。清理它们的唯一方法是执行资源密集型垃圾收集。

在这些情况下,如果有明确删除对象的方法,或者至少是将对象图移回到第0代的方法,那么事情会更容易。

答案 8 :(得分:0)

是的......但有些滥用。

可以滥用C#来实现这一点。 如果您愿意使用Marshal类,StructLayout属性和unsafe code,您可以编写自己的手动内存管理器。

您可以在此处找到该概念的演示:Writing a Manual Memory Manager in C#