为什么这段代码的运行会有很大的不同--GC问题

BlueMountain_1980 2006-09-21 10:45:22
前段时间偶尔在msn上被人问起GC,自己也是不明白,整理了一下不明白的问题。来这里请教。

using System;
using System.Collections.Generic;
using System.Text;
namespace GCDemo
{
class Program
{
static void Main( string[] args )
{
MyClassTemp temp= new MyClassTemp();
//MyClassAdapter temp = new MyClassAdapter();
GCCall();
}
private static void GCCall()
{
Console.ReadLine();
Console.WriteLine( "GC START" );
GC.Collect();
Console.WriteLine( "GC END" );
Console.ReadLine();
}
}
class MyClass : IDisposable
{
#region IDisposable 成员
void IDisposable.Dispose( )
{
throw new Exception( "The method or operation is not implemented." );
}
#endregion
}
class MyClassTemp
{
public MyClassTemp( )
{
Console.WriteLine( "MyClassTemp is Creating" );
}
~MyClassTemp( )
{
Console.WriteLine( "MyClassTemp is Destroying" );
}
}
class MyClassAdapter
{
public MyClassAdapter( )
{
MyClassTemp temp = new MyClassTemp();
}
}
}

-----------------------------------------------------------------
如果把main函数中的代码修改如下 那么得到的结果将会是不同的
//MyClassTemp temp= new MyClassTemp();
MyClassAdapter temp = new MyClassAdapter();

JIT编译main函数,个人感觉好像是把Main函数的所有引用(这里专指引用到heap上的对象)放到root中 MyClassTemp temp= new MyClassTemp(); 这个temp也被放入。那么后来在main函数中调用GC的时候,temp的引用仍然在root中,所以temp并不被GC,而关闭这个控制台程序的时候,temp被GC掉。

如果使用这段代码 MyClassAdapter temp = new MyClassAdapter(); 这个时候main中调用了子函数,此子函数调用结束之后(子函数栈和堆退出了) 这个时候temp这个引用应该是可以从root上移除了,GC的时候,temp被GC.

关乎GC,说得比较清楚地只有jeffrey richer的《Applied Microsoft .Net Framerok Programming》,没有别的书作对照和参考,我也不能很好的理解,如果理解的有错误的地方,望个位路过的留个记号,多多指教。
--------------------------------------------------------------------------------------
http://bluemountain-1980.spaces.live.com/
当我写完这个blog的时候 突然发现这个程序在debug和release状态下的运行结果好像也是不一样的

下面是 李建忠 翻译的《net框架程序设计》中的话,摘抄下来,感觉自己有些糊涂,各位高人给指点一下

P445 当JIT编译器编译一个方法的IL代码时,除了产生本地CPU代码外,JIT还会创建一个内部表。从逻辑上讲,该表的每一个条目都标识者一个方法的本地CPU指令的字节偏移范围,以及该范围中一组包含根的内存地址(或者CPU寄存器)

P446 但是,当应用程序运行在一个调试器中~~~~~~~~~`
...全文
262 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
chenanlin1981 2006-10-01
  • 打赏
  • 举报
回复
帮忙顶一下
xingyaohua 2006-09-30
  • 打赏
  • 举报
回复
up
zhangjianying 2006-09-28
  • 打赏
  • 举报
回复
因为 MyClassTemp 在Main中一直有引用 所以GC认为它是不可以回收的 你可以这样改改程序
static void Main( string[] args )
{
MyClassTemp temp= new MyClassTemp(1);
temp= new MyClassTemp(2);
//temp =null;
// MyClassAdapter temp = new MyClassAdapter();
GCCall();
Console.Read();
}
private static void GCCall()
{
// Console.ReadLine();
Console.WriteLine( "GC START" );
GC.Collect();
Console.WriteLine( "GC END" );
// Console.ReadLine();
}
}

class MyClassTemp
{
private int num;
public MyClassTemp(int num )
{
this.num=num;
Console.WriteLine( "MyClassTemp is Creating"+num );
}
~MyClassTemp()
{

Console.WriteLine( "MyClassTemp is Destroying" +num);
}

}
zhangjianying 2006-09-28
  • 打赏
  • 举报
回复
把你的程序改了下,便于观察
private static void GCCall()
{
//Console.ReadLine();
Console.WriteLine( "GC START" );
GC.Collect();
Console.WriteLine( "GC END" );
// Console.ReadLine();
}
用Mono测试了一下 不同的地方在于:
1) MyClassTemp temp= new MyClassTemp();
//MyClassAdapter temp = new MyClassAdapter();
output:不会出现 MyClassTemp is Destroying
2) //MyClassTemp temp= new MyClassTemp();
MyClassAdapter temp = new MyClassAdapter();
output:出现 MyClassTemp is Destroying

如果你观察一下MyClassAdapter的构造可以看出
public MyClassAdapter( )
{
MyClassTemp temp = new MyClassTemp();
}
也就是说 MyClassTemp 的生存期只在构造函数内,构造结束自然就会调用
MyClassTemp 的析构函数

至于GCCall其实并没有影响什么,要不你注释来运行看看
static void Main( string[] args )
{
MyClassTemp temp= new MyClassTemp();
// MyClassAdapter temp = new MyClassAdapter();
// GCCall();
}
snowmagic 2006-09-27
  • 打赏
  • 举报
回复
结果不同?
结果各是什么?
kandyasp 2006-09-27
  • 打赏
  • 举报
回复
友情帮顶
BlueMountain_1980 2006-09-21
  • 打赏
  • 举报
回复
汗 大意了

class MyClass : IDisposable
{
#region IDisposable 成员
void IDisposable.Dispose( )
{
throw new Exception( "The method or operation is not implemented." );
}
#endregion
}

这个类没有什么用的 忘记去掉了 不好意思

17,748

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET Framework
社区管理员
  • .NET Framework社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧