"使用" vs" = null"和对象的生命周期 [英] "using" vs "= null" and object lifetime

查看:79
本文介绍了"使用" vs" = null"和对象的生命周期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述




最近我已经(现在仍然)修复了我接手的项目中的一些内存泄漏问题

当我得到了这份新工作。在其他问题中,我注意到对于localy创建的对象,

在使用它们之后明确地将它们设置为null有所不同 - 它以某种方式使得

GC会尽快收集它们,例如:


void SomeFunc()

{

MyClass c = new MyClass();

c.CallSomeOtherFunc();

c = null;

}


如果我不'' t putc将null时间收集起来的时间比我明确取消引用

对象要长。这真的很奇怪,因为对象'的生命周期受限于

SomeFunc的主体。但无论如何,我的问题是:第一个例子与此相比有什么不同:


void SomeFunc()

{

使用(MyClass c = new MyClass())

{

c.CallSomeOtherFunc();

}

}


第二种方式看起来更好,避免忘记明确取消引用对象,

但我不确定是否第二种情况正在接受与第一个相同的待遇。


任何建议/想法都将受到高度赞赏!


Thnak you,
Andrey

Hi,

Lately i''ve been (and still am) fixing some memory leaks problems in the project i just took over
when i got this new job. Among the other issues i''ve noticed that for localy created objects it
makes difference to explicitly put them to null after working with them is done - it somehow makes
the GC collect them sooner, like here:

void SomeFunc()
{
MyClass c = new MyClass();
c.CallSomeOtherFunc();
c = null;
}

If i don''t put "c" to null time to get it collected is way longer than if i explicitly dereference
the object. It''s really strange, as it''s obvoius that object''s lifetime is limited by body of
"SomeFunc". But anyway, my question is: is there any difference in the first example compared to this:

void SomeFunc()
{
using (MyClass c = new MyClass())
{
c.CallSomeOtherFunc();
}
}

The second way looks nicer for me and avoids forgetting to explicitly dereference the object,
but i''m not sure if this second case is being treated the same way as the first one.

Any suggestions/ideas would be highly appreciated!

Thnak you,
Andrey

推荐答案

On Thu,2005年2月17日10:02:52 -0500,MuZZy写道:
On Thu, 17 Feb 2005 10:02:52 -0500, MuZZy wrote:
最近,当我得到这份新工作时,我已经(现在仍然)修复了我刚刚接手的项目中的一些内存泄漏问题。在其他问题中,我注意到对于localy创建的对象,
在使用它们之后明确地将它们置为null是不同的 - 它以某种方式使得GC更快地收集它们,就像这里:

void SomeFunc()
{
MyClass c = new MyClass();
c.CallSomeOtherFunc();
c = null;
}

如果我不放c如果我明确地取消引用对象,那么将时间收集起来的时间要长一些。这真的很奇怪,因为对象'的生命周期受到SomeFunc主体的限制。但无论如何,我的问题是:第一个例子与此相比有什么不同:

void SomeFunc()
{
使用(MyClass c = new MyClass())
c.CallSomeOtherFunc();
}
}

第二种方式看起来更好,避免忘记明确取消引用对象,<但我不确定这第二种情况是否与第一种情况相同。
Lately i''ve been (and still am) fixing some memory leaks problems in the project i just took over
when i got this new job. Among the other issues i''ve noticed that for localy created objects it
makes difference to explicitly put them to null after working with them is done - it somehow makes
the GC collect them sooner, like here:

void SomeFunc()
{
MyClass c = new MyClass();
c.CallSomeOtherFunc();
c = null;
}

If i don''t put "c" to null time to get it collected is way longer than if i explicitly dereference
the object. It''s really strange, as it''s obvoius that object''s lifetime is limited by body of
"SomeFunc". But anyway, my question is: is there any difference in the first example compared to this:

void SomeFunc()
{
using (MyClass c = new MyClass())
{
c.CallSomeOtherFunc();
}
}

The second way looks nicer for me and avoids forgetting to explicitly dereference the object,
but i''m not sure if this second case is being treated the same way as the first one.




你的第二种情况与第一。另一种写

秒的方法是:


void SomeFunc()

{

MyClass c = new MyClass()

尝试

{

c.CallSomeOtherFunc();

}

终于

{

c.Dispose();

}

}


所以在你的第一个例子中,你将c设置为null,然后才会超出

范围。在你的第二个例子中,你没有将c设置为null,但你是

保证无论发生什么都会调用c.Dispose()。

-

Tom Porterfield



Your second case is not the same as the first. Another way to write the
second would be:

void SomeFunc()
{
MyClass c = new MyClass()
try
{
c.CallSomeOtherFunc();
}
finally
{
c.Dispose();
}
}

So in your first example you are setting c to null before it goes out of
scope. In your second example you are not setting c to null, but you are
guaranteeing that c.Dispose() will be called no matter what happens.
--
Tom Porterfield


Andrey,


见内联:
Andrey,

See inline:
最近我当我得到这份新工作时,我刚刚(并且仍在)修复了我刚刚接手的
项目中的一些内存泄漏问题。在其他问题中我已经注意到,对于localy创建的对象,使用它们之后明确地将它们置为null是不同的 - 它以某种方式
使GC更快地收集它们,像这里:

void SomeFunc()
{
MyClass c = new MyClass();
c.CallSomeOtherFunc();
c = null ;
}


这取决于它的编译方式。如果你是在调试模式下进行编译,那么是b $ b然后是的,它会使GC更快(尽管有多快,但是因为c之后很快就会释放,所以b b b b b b b b b到期退出方法需要

)。原因是在调试

模式下编译的代码在不再使用时不会释放引用。然而,当为发布模式编译

时,实际上你正在使用c = null扩展对象的生命周期。分配。如果语句

不存在,编译器会在调用CallSomeOtherFunc之后意识到c指向的对象不再需要
(除非引用
c指向的
存储在调用CallSomeOtherFunc的其他地方,

然后将其设置为null,使其有资格获得GC。

但是,使用c = null语句,编译器意识到(虽然我不知道这里是否可以进行激励优化),这是另一个调用所需的
,并且对象指向如果我没有c,那么在获得作业之后,它就不会被取消。

如果我不放c如果我明确地取消引用该对象,那么将其收集的时间更长。它真的很奇怪,因为它是obvius
对象'的生命周期受到SomeFunc主体的限制。


这不是真的。 GC尚未预先确定。为什么GC在应用程序的一次运行中很快就会发生,而不是在另一次运行的

应用程序中很晚才能确定。您的

应用程序之外还有其他因素可以强制GC。一次运行一个GC的时间
应用程序的
对应用程序中另一个运行的GC意味着很少。

但无论如何,我的问题是:有没有第一个例子中的差异
与此相比:

void SomeFunc()
{
使用(MyClass c = new MyClass())
{
c.CallSomeOtherFunc();
}


第二种方式看起来更好,避免忘记明确地取消引用对象,但我不确定这第二个案件的处理方式是否与第一个案件相同。


完全是一个单独的问题。只是因为你实现了

IDispose,这并不意味着该对象不再需要GC。

如果你有IDispose,那就意味着你需要通过调用执行

IDispose的Dispose方法以某种方式管理

对象的生命周期。实现IDispose通常有两个原因。

第一个,也是最常见的,因为实例正在坚持使用某些非托管资源来支付
,而你需要尽快释放它。

在这种情况下实现IDispose时,你还需要实现一个

终结器(析构函数,尽管术语不正确,IMO) 。如果人们不打电话给Dispose,那么终结者

就是一个安全保障。如果还没有完成,它将基本上释放非托管资源。


终结是一个昂贵的过程。该对象基本上是

重新确定并放置在终结队列中,然后执行终结器

。如果在一个对象上调用Dispose,则不需要确定
,这就是为什么你在Dispose的

实现中看到对GC.SuppressFinalize的调用。 ,而不是终结者本身。由于

终结器和Dispose做同样的事情,如果调用Dispose,你可以有效地告诉GC不要敲定你,并避免代价高昂的开销。 />

但是,即使你说你要压制终结,

对象仍然需要进行GCed。即使在调用Dispose时,仍然必须在此对象上发生回收内存

的过程。然而,

它是你真正不在乎的东西,因为它只是记忆,而你已经放弃了对它的控制(对于大部分)同意在

CLR中运行(这是GC的目的,担心这些事情,而不是你的)。


禁止终结只意味着终结者不会被调用,它不会意味着对象已被GC。


使用的第二个原因IDispose是因为你需要一些确定性的

终结。例如,在方法中的操作之后,您可能总是需要设置一些

变量。在这种情况下,生成一个实现IDisposable的
类可能是一个好主意,因为你可以在退出using块时将
恢复为变量(而不是

显式记住编写try / catch / finally块代码。


在你的情况下,你属于使用IDispose的第一个类别。

如果你真的有一个

非托管资源,那么使用using语句将非常重要。如果你没有,并且它只是一个

常规类,那么使用using语句将无法工作,并且实现IDispose的
也无济于事。


希望这会有所帮助。


-

- Nicholas Paldino [.NET / C#MVP]

- mv*@spam.guard.caspershouse.com

任何建议/想法都将是非常感谢!

Thnak you,
Andrey
Lately i''ve been (and still am) fixing some memory leaks problems in the
project i just took over when i got this new job. Among the other issues
i''ve noticed that for localy created objects it makes difference to
explicitly put them to null after working with them is done - it somehow
makes the GC collect them sooner, like here:

void SomeFunc()
{
MyClass c = new MyClass();
c.CallSomeOtherFunc();
c = null;
}
This depends on how it is compiled. If you are compiling in debug mode,
then yes, it will make it GC faster (although how much faster is
questionable since c would have been released very quickly afterwards, due
to exiting the method). The reason for this is that code compiled in debug
mode will not have references released when they are no longer used. When
compiled for release mode, however, you are actually ^extending^ the
lifetime of your object with the "c = null" assignment. If the statement
was not there, the compiler would realize that the object pointed to by c is
no longer needed after the call to CallSomeOtherFunc (unless the reference
pointed to by c is stored somewhere else in the call to CallSomeOtherFunc),
and then set it to null, allowing it to become eligible for GC.

However, with the "c = null" statement, the compiler realizes (although
I don''t know if agressive optimizations here can pick it up) that it is
needed for another call, and the object pointed to by c isn''t made eligible
until ^after^ the assignment.
If i don''t put "c" to null time to get it collected is way longer than if
i explicitly dereference the object. It''s really strange, as it''s obvoius
that object''s lifetime is limited by body of "SomeFunc".
This isn''t true. GCs are not pre-determined. Why a GC occurs very
quickly in one run of the app as opposed to very late in another run of the
app is not easily determinable. There are other factors outside your
application which can force a GC as well. The timing of one GC in one run
of the app vs a GC of another run in an app means very little.
But anyway, my question is: is there any difference in the first example
compared to this:

void SomeFunc()
{
using (MyClass c = new MyClass())
{
c.CallSomeOtherFunc();
}
}

The second way looks nicer for me and avoids forgetting to explicitly
dereference the object,
but i''m not sure if this second case is being treated the same way as the
first one.
This is a separate issue completely. Just because you implement
IDispose, it doesn''t mean that the object doesn''t need to be GCed anymore.
If you have IDispose, it means that you need to manage the lifetime of the
object in some way by calling the Dispose method on the implementation of
IDispose. There are usually two reasons you implement IDispose.

The first, and most common, is because the instance is holding on to
some unmanaged resource, and you need to release it as soon as possible.
When implementing IDispose in this scenario, you also need to implement a
finalizer (destructor, although the term is incorrect, IMO). The finalizer
is meant to be a safeguard if people don''t call Dispose. It will basically
release the unmanaged resource if it hasn''t been done already.

Finalization is an expensive process. The object is basically
ressurected and placed in a finalization queue, and then has the finalizer
executed. If Dispose is called on an object, it doesn''t need to be
finalized, which is why you see a call to GC.SuppressFinalize in the
implementation of Dispose, and not the finalizer itself. Since the
finalizer and Dispose do the same thing, if Dispose is called, you can
effectively tell the GC to not finalize you, and avoid that costly overhead.

However, even if you say that you are going to suppress finalization,
the object still has to be GCed. The process of having the memory reclaimed
still has to occur on this object, even when Dispose is called. However,
it''s something you really don''t care about, because it''s just memory, and
you gave up control of that (for the most part) by agreeing to run in the
CLR (that''s the purpose of the GC, to worry about these things, not yours).

Suppressing finalization only means the finalizer will not be called, it
doesn''t mean that the object has been GCed.

The second reason to use IDispose is because you need some deterministic
finalization to take place. For example, you might always need some
variable set back after an operation in a method. In this case generating a
class which implements IDisposable might be a good idea, since you can
revert the variable back when the using block is exited (instead of having
to explicitly remembering to code a try/catch/finally block).

In your case, you fall into the first category for using IDispose.
Using the using statement will be important, if you actually have an
unmanaged resource you are holding on to. If you do not, and it is just a
regular class, then using the using statement will not work, and
implementing IDispose will not help either.

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

Any suggestions/ideas would be highly appreciated!

Thnak you,
Andrey



Tom Porterfield写道:
Tom Porterfield wrote:
在2005年2月17日星期四10:02:52 -0500,MuZZy写道:

On Thu, 17 Feb 2005 10:02:52 -0500, MuZZy wrote:

最近我一直(并且仍在)解决一些内存泄漏问题当我得到这份新工作时,我接手了这个项目。在其他问题中,我注意到对于localy创建的对象,
在使用它们之后明确地将它们置为null是不同的 - 它以某种方式使得GC更快地收集它们,就像这里:

void SomeFunc()
{
MyClass c = new MyClass();
c.CallSomeOtherFunc();
c = null;
}

如果我不放c如果我明确地取消引用对象,那么将时间收集起来的时间要长一些。这真的很奇怪,因为对象'的生命周期受到SomeFunc主体的限制。但无论如何,我的问题是:第一个例子与此相比有什么不同:

void SomeFunc()
{
使用(MyClass c = new MyClass())
c.CallSomeOtherFunc();
}
}

第二种方式看起来更好,避免忘记明确取消引用对象,<但是我不确定第二种情况是否与第一种情况相同。
Lately i''ve been (and still am) fixing some memory leaks problems in the project i just took over
when i got this new job. Among the other issues i''ve noticed that for localy created objects it
makes difference to explicitly put them to null after working with them is done - it somehow makes
the GC collect them sooner, like here:

void SomeFunc()
{
MyClass c = new MyClass();
c.CallSomeOtherFunc();
c = null;
}

If i don''t put "c" to null time to get it collected is way longer than if i explicitly dereference
the object. It''s really strange, as it''s obvoius that object''s lifetime is limited by body of
"SomeFunc". But anyway, my question is: is there any difference in the first example compared to this:

void SomeFunc()
{
using (MyClass c = new MyClass())
{
c.CallSomeOtherFunc();
}
}

The second way looks nicer for me and avoids forgetting to explicitly dereference the object,
but i''m not sure if this second case is being treated the same way as the first one.



你的第二种情况与第一种情况不同。另一种写
的方法是:

void SomeFunc()
{
MyClass c = new MyClass()
尝试
{
c.CallSomeOtherFunc();
}
终于
{
c.Dispose();
}
}

所以在你的第一个例子中,你将c设置为null,然后才会超出
范围。在你的第二个例子中,你没有将c设置为null,但是你保证无论发生什么都会调用c.Dispose()。


Your second case is not the same as the first. Another way to write the
second would be:

void SomeFunc()
{
MyClass c = new MyClass()
try
{
c.CallSomeOtherFunc();
}
finally
{
c.Dispose();
}
}

So in your first example you are setting c to null before it goes out of
scope. In your second example you are not setting c to null, but you are
guaranteeing that c.Dispose() will be called no matter what happens.




谢谢!

所以如果我更关心较短的物体寿命,我宁愿这样做:


void SomeFunc()

{

MyClass c = new MyClass()

c.CallSomeOtherFunc();

c.Dispose();

c = null;

}


比使用使用?

对吗? br />



Thank you!
So if i''m more concerned about shorter object lifetime, i''d rather do this:

void SomeFunc()
{
MyClass c = new MyClass()
c.CallSomeOtherFunc();
c.Dispose();
c = null;
}

than use "using"?
Right?


这篇关于&QUOT;使用&QUOT; vs&quot; = null&quot;和对象的生命周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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