引用类型赋值“.NET技术”为null与加速垃圾回收

  在标准的Dispose模式中,提到了需要及时释放资源,却并没有进一步细说让引用等于null是否有必要。

  有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾。其他人则认为这没有任何帮助。是否赋值为null的问题首先在方法的内部被人提起。现在,为了更好的阐述提出的问题,我们来撰写一个Winform窗体应用程序。如下:


private void button1_Click(object sender, EventArgs e)
{
Method1();
Method2();
}

private void button2_Click(object sender, EventArgs e)
{
GC.Collect();
}

private void Method1()
{
SimpleClass s = new SimpleClass("method1");
s = null;
//其它无关工作代码(这条注释源于回应回复的朋友的质疑)
}
private void Method2()
{
SimpleClass s = new SimpleClass("method2");
}
}

class SimpleClass
{
string m_text;

public SimpleClass(string text)
{
m_text = text;
}

~SimpleClass()
{
MessageBox.Show(string.Format("SimpleClass Disposed, tag:{0}", m_text));
}
}

  先点击按钮1,再点击按钮2释放,我们会发现:

  q 方法Method2中的对象先被释放,虽然它在Method1之后被调用;

  q 方法Method2中的对象先被释放,虽然它不像Method1那样为对象引用赋值为null;

  在CLR托管应用程序中,存在一个根的概念,类型的静态字段、方法参数以及局部变量都可以作为根存在(值类型不能作为根,只有引用类型的指针才能作为根)。

  上面的两个方法中各自的局部变量,在代码运行过程中会在内存中各自创建一个根.在一次垃圾回收中,垃圾回收器会沿着线程栈上行检查根。检查到方法内的根时,如果发现没有任何一个地方引用了局部变量,则不管是否为变量赋值为null,都意味着该根已经被停止掉。然后垃圾回收器发现该根的引用为空,同时标记该根可被释放,这也表示着Simple类型对象所占用的内存空间可被释放。所以,在上面的这个例子中,为s指定为null丝毫没有意义(方法的参数变量也是这种情况)。

  更进一步的事实是,JIT编译器是一个经过优化的编译器,无论我们是否在方法内部为局部变量赋值为null,该语句都会被忽略掉

s = null;

  在我们将项目设置为Release模式下,上面的这行代码将根本不会被编译进运行时内。

  正式由于上面这样的分析,很多人认为为对象赋值为null完全没有必要。但是,在另外一种情况下,却要注意及时为变量赋值为null。那就是类型的静态字段。为类型对象赋值为null,并不意味着同时为类型的静态字段赋值为null:


private void button1_Click(object sender, EventArgs e)
{
SimpleClass s = new SimpleClass("test上海企业网站设计与制作n style="color: #800000;">");
}

private void button2_Click(object sender, EventArgs e)
{
GC.Collect();
}
}

class SimpleClass
{
static AnotherSimpleClass asc = new AnotherSimpleClass();
string m_text;

public SimpleClass(string text)
{
m_text = text;
}

~SimpleClass()
{
//asc = null;
MessageBox.Show(string.Format("SimpleClass Disposed, tag:{0}上海企业网站制作style="color: #800000;">", m_text));
}
}

class AnotherSimpleClass
{
~AnotherSimpleClass()
{
MessageBox.Show("AnotherSimpleClass Disposed");
}
}

  以上代码运行的结果使我们发现,当执行垃圾回收,当类型SampleClass对象被回收的时候,类型的静态字段asc并没有被回收。

  必须要将SimpleClass的终结器中注释的那条代码启用。

  字段asc才能被正确释放(注意,要点击两次释放按钮。这是因为一次垃圾回收会仅仅首先执行终结器)。之所以静态字段不被释放(同时赋值为null语句也不会像局部变量那样被运行时编译器优化掉),是因为类型的静态字段一旦被创建,该根就一直存在。所以垃圾回收器始终不会认为它是一个垃圾。非静态字段不存在这个问题。将asc改为非静态,再次运行上面的代码,会发现asc随着类型的释放而被释放。

  上文代码的例子中,让asc=null是在终结器中完成的,实际工作中,一旦我们感觉到自己的静态引用类型参数占用内存空间比较大,并且使用完毕后不再使用,则可以立刻将其赋值为null。这也许并不必要,但这绝对是一个好习惯。试想一下在一个大系统中,那些时不时在类型中出现的静态变量吧,它们就那样静静地呆在内存里,一旦被创建,就永远不离开,越来越多,越来越多。

时间: 2024-09-20 18:34:58

引用类型赋值“.NET技术”为null与加速垃圾回收的相关文章

改善C#程序的建议5:引用类型赋值为null与加速垃圾回收

原文:改善C#程序的建议5:引用类型赋值为null与加速垃圾回收 在标准的Dispose模式中(见前一篇博客"C#中标准Dispose模式的实现"),提到了需要及时释放资源,却并没有进一步细说让引用等于null是否有必要. 有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾.其他人则认为这没有任何帮助.是否赋值为null的问题首先在方法的内部被人提起.现在,为了更好的阐述提出的问题,我们来撰写一个Winform窗体应用程序.如下: privatevoid button

一起谈.NET技术,引用类型赋值为null与加速垃圾回收

在标准的Dispose模式中,提到了需要及时释放资源,却并没有进一步细说让引用等于null是否有必要. 有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾.其他人则认为这没有任何帮助.是否赋值为null的问题首先在方法的内部被人提起.现在,为了更好的阐述提出的问题,我们来撰写一个Winform窗体应用程序.如下: private void button1_Click(object sender, EventArgs e) { Method1(); Method2(); } pr

关于将临时变量置为null是否有助于快速垃圾回收

"将不再使用的临时变量立即置为null是否有助于垃圾回收"的话题好像有不少人争论过. 首先,我们要理解GC回收垃圾数据的标准是通过路径检查,看是否还有引用指向某个对象.如果不再有引用指向这个待回收的对象,那么GC会将其放入待回收队列.从这个理论上来说,适时将不再使用的变量置为null是有助于垃圾回收的.但是,进一步理解GC的工作模式,我们会发现如下几个问题. 1. GC只是将其置于待回收队列,并不一定立即回收(需要一定的条件).2. GC并不会在变量置为null时启动回收动作. 所以只

VR技术会不会加速传统医疗的全面革新?

VR技术会不会加速传统医疗的全面革新? 会! 必须承认,当初移动医疗异军突起的时候,"颠覆" 之声不绝于耳.然而直到今年,移动医疗的时代已经结束了,传统医疗丝毫未变.所以现如今,VR 医疗会不会是又一次心血来潮?会不会多年后因为碌碌无为而被渐渐遗忘?我认为不会,因为 VR 医疗与移动医疗之间存在着价值观上的根本区别: 移动医疗改变传统医疗的思路是 "打破一个旧世界,创造一个新世界",企图凭借一己之力完全颠覆传统医疗.VR 医疗不是.虽然 VR 医疗的出现会在很多方面

遍历-C# List<T> 引用类型赋值问题

问题描述 C# List<T> 引用类型赋值问题 今天用泛型foreach遍历赋值引用类型.碰到一个很坑爹的问题,求解答? 入下图:第一例的数据被第二列数据覆盖 解决方案 List.Add(T) 引用类型与值类型 解决方案二: lll.add(item); 添加的是list 所以你的l里面每一个元素都是list 可以直接添加 for (int i = 0; i < 2;i++ ) { List list = new List(); list.Add(new class1(Guid.New

垃圾回收机制与引用类型

 Java语言的一个重要特性是引入了自动的内存管理机制,这样一来,开发人员就不需要自己来管理应用中的内存了.C/C++开发人员需要通过malloc/free和new/delete等函数来显式的分配和释放内存.这对开发人员提出了比较高的要求,因为这些方法使用不当很容易造成内存访问错误和内存泄露等严重问题.一个最常见的问题是 "悬挂引用(dangling references)",即一个引用或指针所指向的内存区块已经被错误的回收并重新分配给新的对象了,如果程序继续使用这个引用或指针的话会,

【译】垃圾回收,引用类型和五种可达性-强、软、弱、虚、不可达

Java虚拟机有5个不同级别的对象的可达性. ●强可达(Strongly reachable) 如果一个对象可以被一些线程直接使用而不用通过其他引用对象(reference objects),那么它就是强可达.一个新创建的对象对创建它的线程来讲就是强可达的. 这是我们知道并且一直在使用的引用类型(译注:通常被new出来的对象都是强可达的,他们的引用就是强引用).任何通过强引用所使用的对象(在一个活动线程中)都不会被GC回收. ●软可达(Softly reachable) 如果一个对象没有强可达性

C#技术漫谈之垃圾回收机制(GC)

GC的前世与今生 虽然本文是以.net作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是GC的第一次出现.Lisp的程序员认为内存管理太重要了,所以不能由程序员自己来管理. 但后来的日子里Lisp却没有成气候,采用内存手动管理的语言占据了上风,以C为代表.出于同样的理由,不同的人却又不同的看法,C程序员认为内存管理太重要了,所以不能由系统来管理,并且讥笑Lisp程序慢如乌龟的运行速度.

Java技术专题之JVM逻辑内存回收机制研究图解版

一.引言 JVM虚拟机内存回收机曾迷惑了不少人,文本从JVM实现机制的角度揭示JVM内存回收的原理和机制. 一.Java平台逻辑架构 二.JVM物理结构 通过从JVM物理结构图我们可以看到: 1.JVM两个子系统:类加载子系统和执行引擎子系统: 2.JVM两个组件:本地接口方法组件和内存空间组件. 2.JVM内存空间分为:Java堆,Java栈.方法区和本地方法区 关键词:我们经常讨论的JVM内存回收机制就是指Java堆内存回收机制. 四.JVM内存组成结构 上图所示四部分即为JVM内存组成结构