GC!为什么不参考? [英] GC! Why not ref count?

查看:60
本文介绍了GC!为什么不参考?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++是一门很棒的语言。你可以在堆栈上实例化一个对象,获取你需要的任何资源,然后在析构函数中释放它们

。对象析构函数在

正确顺序(相反顺序)中调用,并保证在对象超出范围时调用



不幸的是,在C#(或Java)中并非如此,因为你没有告诉垃圾收集器什么时候运行。在C#

你可以调用Dispose(假设它已经实现),但是你

你仍然可能有几个引用无效的

物体漂浮在周围。或者你可以使用using语句获得
的优势如果类实现了

IDispose,但是如果你需要使用

几个嵌套使用它会变得难以处理块。


那么为什么C#(和Java)的开发人员没有引用

计数对象?当然,实现引用计数是一件很简单的事情,并且保证在对象的最后一次引用设置为
$ b时调用

析构函数$ b null。 GC仍然可以定期运行以清理和重新组织内存,但至少资源清理

问题已经解决了。

我缺少什么?


谢谢。

解决方案



Ron James <滚装******* @ noapsm.rojacs.com>在消息中写道

news:09 **************************** @ phx.gbl ... < blockquote class =post_quotes> C ++是一门很棒的语言。您可以在堆栈上实例化一个对象,抓取您需要的任何资源,并在析构函数中释放它们。对象析构函数以正确的顺序(相反的顺序)调用,并保证在对象超出范围时调用。


只有堆栈分配的对象才有效。如果你有堆分配

对象,那么你负责在完成

对象时调用delete。这导致很多问题......内存泄漏(没有删除),调用

删除无效指针(崩溃!),调用删除对象仍然需要

(崩溃!或腐败)。 GC之所以受欢迎是因为它可以让

程序员免于明确管理内存分配的需要。

不幸的是,在C#(或Java)中不是这样,因为你
无法判断垃圾收集器何时运行。在C#
中你可以调用Dispose(假设它已经实现了),但是你还是可能有几个引用浮动的无效
对象。或者你可以使用using语句的优点如果类实现了IDispose,但是如果你需要几个嵌套的使用块,这可能会变得笨拙。


你不了解Dispose模式。对于包含对非托管资源的引用的类,例如文件

句柄,窗口句柄,数据库连接,套接字句柄等,只实现了处理

。这些

是有限的操作系统资源,需要尽快返回。用

换句话说,你不想等待你的终结方法被要求释放那些资源。不仅如此,重写

finalize会对GC性能产生负面影响 - 因为它需要

才能完全破坏对象。所以要解决这个问题,MS已经提供了基于模式的方法来处理这些类型的资源

通过IDisposable接口。通常所有必要的清理都是从finalize方法和Dispose方法中调用

,并添加了

步骤,系统将调用System.GC.SuppressFinalize。处理方法。

这可以让你确保最终清理非托管资源 -

即使开发人员忘记调用Dispose,但奖励那些做的事情

记住在GC时删除性能命中。

那么为什么C#(和Java)的开发人员不参考
计数对象?当然,实现引用计数是一件简单的事情,并且保证在对象的最后一个引用设置为
null时调用
析构函数。 GC仍然可以定期运行以清理和重新组织内存,但至少资源清理问题已经解决了。




主要是因为引用计数有几个副作用。

1)性能 - 通常引用计数方案表现不如

作为在Java和.NET中实现的GC方案一个简单的事实,他们

必须是线程安全的,这意味着同步必须到位。


2)参考计数很容易搞砸。通常使用

方法来增加或减少Ref计数,这取决于

开发人员或运行时,以确保以均衡的方式调用它们。


3)引用计数并不能很好地处理对象周期(又称循环

引用)。这是VB.CLASSIC中内存泄漏的主要来源之一。


事实上,C#/ Java使用的GC风格更加高效和美元。 b $ b不易出错,然后引用计数...


Tom Shelton


Ron,


这在.NET的早期就被大量*争论过了。我建议你阅读

这篇文章来了解设计师们的想法

http://discuss.develop.com/archives/...OTNET&P=R28572


Mattias


-

Mattias Sj?gren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/

请回复新闻组。


查看一些其他OO语言,这些语言可以处理大量数据

的对象和处理内存管理。你会看到他们全部

放弃引用计数(标记和扫描)有两个原因


1 - 这是非常昂贵的。您必须每次访问每个节点。

至少2次(标记和扫描通过),再次,如果你实际上是

使用它。 Slooooooowwwwwwwwwwwwwww。


2 - 它并没有利用这种情况。大多数物品要么被创造了

并且在他们抽出两次呼吸之前被吹走了,要么就像我的旧袜子一样留在我身边

。在90年代早期,Smalltalk和CLOS都代代相传,但是我希望这些领域变得更加可观。

目前还是深奥。

C++ is a great language. You can instantiate an object on
the stack, grab whatever resources you need, and free them
in the destructor. Object destructors are called in the
correct order (the reverse order), and are guaranteed to
be called when the object goes out of scope.

Unfortunately this is not so in C# (or Java) since you
cannot tell when the Garbage Collector will run. In C#
you can call Dispose (assuming it''s implemented), but you
you still might have several references to a invalid
object floating around. Alternatively you can take
advantage of the using statement IF the class implements
IDispose, however this can become unwieldy if you need
several nested using blocks.

So why did the developers of C# (and Java) not reference
count objects? Surely it would have been a simple matter
to implement reference counting, and guarantee calling the
destructor when the last reference to an object was set to
null. The GC could still run periodically to clean up and
re-organize memory, but at least the resource cleanup
problem would have been solved.

What am I missing?

Thanks.

解决方案


"Ron James" <Ro*******@noapsm.rojacs.com> wrote in message
news:09****************************@phx.gbl...

C++ is a great language. You can instantiate an object on
the stack, grab whatever resources you need, and free them
in the destructor. Object destructors are called in the
correct order (the reverse order), and are guaranteed to
be called when the object goes out of scope.
That is only true of stack allocated objects. If you have heap allocated
objects then you are responsible for calling delete when done with the
object. This causes many problems... Memory leaks (no delete), calling
delete on invalid pointer (crash!), calling delete to an object that is
still needed (crash! or corruption). GC is popular because it frees the
programmer from the need to explicitly manage memory allocation.
Unfortunately this is not so in C# (or Java) since you
cannot tell when the Garbage Collector will run. In C#
you can call Dispose (assuming it''s implemented), but you
you still might have several references to a invalid
object floating around. Alternatively you can take
advantage of the using statement IF the class implements
IDispose, however this can become unwieldy if you need
several nested using blocks.
You are not understanding the Dispose pattern. Dispose is only implemented
for classes that hold references to unmanaged resources - such as file
handles, window handles, database connections, socket handles, etc.) These
are limmited OS resources, that need to be returned as soon as possible. In
other words, you don''t want to wait around for your finalize method to be
called for those resources to be released. Not only that, overriding
finalize has negative consequences for GC performance - because it requires
to GC''s to completely destroy the object. So do get around that, MS has
provided a pattern based approach for dealing with these types of resources
via the IDisposable interface. Generally all necessary clean up is called
from both the finalize method as well as the Dispose method, with the added
step that System.GC.SuppressFinalize will be called in the Dispose method.
This lets you insure that unmanaged resources are cleaned up eventually -
even if a developer forgets to call Dispose, but rewards those that do
remember by removing the performance hit at GC time.
So why did the developers of C# (and Java) not reference
count objects? Surely it would have been a simple matter
to implement reference counting, and guarantee calling the
destructor when the last reference to an object was set to
null. The GC could still run periodically to clean up and
re-organize memory, but at least the resource cleanup
problem would have been solved.



Mostly because ref counting has several side affects.
1) Performance - generally reference counting schemes do not perform as well
as GC schemes as implemented in Java and .NET for the simple fact that they
have to be thread safe, which mean syncronization must be in place.

2) Referecne counting is easy to screw up. Often they are implmented using
methods that increment or decrement the Ref count and it is up to the
developer or the runtime to make sure these are called in a balanced manner.

3) Ref counting doesn''t deal with object cycles well (aka circular
references). This is one of the major source of memory leaks in VB.CLASSIC.

The fact is that the style of GC used by C#/Java is much more effiecient and
less prone to error then reference counting...

Tom Shelton


Ron,

This was debated *a lot* in the early days of .NET. I suggest you read
this piece to get an idea of how the designers were thinking

http://discuss.develop.com/archives/...OTNET&P=R28572

Mattias

--
Mattias Sj?gren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/
Please reply only to the newsgroup.


Check out some of the other OO languages which do handle large numbers
of objects and deal with memory management. You''ll see they all
abandoned reference counting (mark and sweep) for two reasons

1 - It''s very expensive. You have to visit every node every pass. At
least 2 times (mark and sweep pass) and once again if you''re actually
using it. Slooooooowwwwwwwwwwwwwww.

2 - It doesn''t exploit the situation. Most objects are either created
and blown away before they''ve drawn two breaths, or they stay around
like my old socks. Smalltalk and CLOS both headed for generation
scavenging in the early 90''s, but I expect the fields become even more
abstruse at this point.


这篇关于GC!为什么不参考?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆