柚子Nan--回归原点

Everything can be as easy as you like or as complex as you need.
posts - 231, comments - 972, trackbacks - 17, articles - 29
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

垃圾收集学习笔记(第2章)

Posted on 2004-05-31 14:17 柚子Nan 阅读(1080) 评论(5)  编辑 收藏 所属分类: [技术.Net]

关于GCGeneration的一个疑惑

 

有关于GC.MaxGeneration的说明参考微软的MSDN

 

我在测试GetGeneration()方法的时候发现一个问题

背景如下:

两个类FirstClassSomeClass

FirstClass

{

       private int MaxLine = 1000;

       ~FirstClass()  

       {

       }

       // 这个函数将不能通过编译

       // protected override void Finalize()

       // {               

       //     MaxLine = 0;

       // }

       public void GenerateSomeRubbish()

       {

              string strMM;

              for(int i=0;i<MaxLine;i++)

              {

                     strMM = new string('a',MaxLine);

              }

       }

}

public class SomeClass

{

       public SomeClass()

       {

       }

       public void sameToUp()

       {

              string str;

              for(int i=0;i<10;i++)

              {

                      str = new string('a',10);

              }

       }

}

在一个Main中测试GC.GetGeneration()方法。

FirstClass fObj = new FirstClass();

SomeClass  sObj = new SomeClass();

1fObj.GenerateSomeRubbish();

2sObj.sameToUp();

GC.GetGeneration(fObj);//返回2

GC.GetGeneration(sObj);//返回2

 

如果屏蔽1、两个都返回0

如果屏蔽2、两个都返回2

如果都屏蔽,都返回0

 

在上边的Code中,FirstClassSomeClass并没有很大的区别。

表面上来看,其实都是产生一堆新的字符串对象而已,在寻找原因…….

1、难道是因为有个析构函数,后来发现删除后也没有关系。

2、难道是因为定义了一个局部的变量MaxLine,改动后也不是。

3、莫非是MaxLine的大小有影响?

我就把MaxLine改成了100,重新执行GC.GetGeneration(fObj),发现返回的是1,看来确实就是了。

这就有趣了,那就测试一下所有的大小了J

 

System.IO.StreamWriter sw = new System.IO.StreamWriter(@"d:\kkk.txt");

for(int i=0; i< 10000; i++)

{

       fObj.GenerateSomeRubbish(i);//这里改动了GenerateSomeRubbish,只是增加一个参数

       sw.Write(i.ToString()+"\t");

       sw.WriteLine(GC.GetGeneration(fObj));

}

 

哈哈,结果如下

数字

代数

0

0

1

0

2

0

.....

 

48

0

49

0

50

1

51

1

....

 

485

1

486

1

487

2

488

2

 

不知道为什么?为什么会产生代数不相同的情况?

难道是微软的.net Framework规定了第1代的垃圾数量是50个,然后第2代的垃圾是427个,第三代的垃圾就不限制了?

Feedback

#1楼    回复  引用    

2004-05-31 15:10 by 冬瓜 [未注册用户]
应该是跟代龄的容量有关。
Jeffrey的书里提到过。

#2楼    回复  引用  查看    

2004-05-31 16:02 by juqiang      
垃圾数量是否有关,我不清楚。不过GC中每个Generation的大小,还是比较固定的。
0代,一般为256K。这个值其实和你的CPU的L2 cache大小相关。
1代,一般为10M,这个值和啥相关,忘记了。
2代,无限增长的,受制于普通进程所能应用的最大内存(2G少一些左右)

#3楼    回复  引用  查看    

2004-05-31 21:12 by sumtec      
楼上的给出了大概的解释,这里我给出一些详细的补充:
1、内存分配的时候,都是优先在Gen0里面进行的,除非大小超出了Gen0的承受能力——那就直接在可以承受的Gen里面分配。
2、分配了的对象并不实时地进行追踪,也就是说你不引用了并不会立刻释放着一块内存的,或者说实际上还是占用着这块内存的。
3、Gen0满了的时候,GC会试图将Gen0里面正在被引用的东西统统都搬到Gen1里面。这个是基于“长时间不释放的对象在相对长的时间内不可能被释放,使用频率也更低”的理论而“放松”管理,GC更多时候关注的是Gen0里面的事情。由于Gen0比较小,这样有利于提高GC效率。

由于实际上GC只会把你目前引用的东西搬到Gen1,因此实际上只会搬2kb的一个实例——String('a', MaxLine)。(一个字符占2bytes,.NET下面的字符是Unicode的)因此实际上我记得Gen0/Gen1好像没有楼上说的那么大。实际上即使MaxLine个有MaxLine个字符的字符串被引用,整个的占用大小也应该在2MB左右,不太可能因此被转移到Gen2。我估计转移的原因并不是Gen1满了,而是GC在整理Gen0的时候,偶尔顺带整理Gen1的内容,把那些Recently unused的内容丢到Gen2里面去。

(我怎么记得Gen0对应的是lv1 cache的大小,Gen1对应的是lv2 cache的大小……难道我记错了?)

#4楼    回复  引用  查看    

2004-06-01 08:25 by Koffer      
看来确实是跟GenX的容量有关,具体是多少,我没有看过类似的书,sumtec说的应该没错:)
其实内存是否回收,都不是我们个人所能够控制的, .net CLR会自动地处理这些事情的。
看到Recently unused使我想起来,OS中的最近最少使用算法,二次回收算法,好像都是讲的内存回收的经典算法。
看来关于Generation1中的垃圾如何移动,还有待于继续关注!

#5楼    回复  引用  查看    

2004-06-07 10:46 by juqiang      
对于Generations,clr中目前是设置了3代。但是这个数字不是固定的,以后ms可能会改变。
我的理解,0-->1和1--->2,移动的方法是一样的,只不过临界条件不一样。

还有一个细节问题,object的大小如果大于85k左右,gc发生后,却不会压缩该object所占的内存。

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2004-06-05 20:23 编辑过