读书人

《您不常用的c#之五》:Thread与Thread

发布时间: 2012-10-08 19:54:56 作者: rapoo

《你不常用的c#之五》:Thread与ThreadPool的内存之战

?红色部分,31个Thread,对应着31个Context,每个线程在windows底层都是一个内核对象和一个栈空间,内核对象存放一些线程的统计信息,比如计数器以及一个上下文,就是我上次执行到那里等。而栈空间则是用来存放线程参数等。?

4,我们来具体看下这些Thread们的MethodTable

?windbg已经很清楚的告诉我们, 
一个对象可以
1,在栈上
2,在一个GCHandle里(可以执行!GCHandles命令查看)
3,在FinalizeQueue里
4,是一个对象的成员
难道对象就必定在以上的“四行”之中吗?答案是不一定,还有个Gchandleleaks,就是你在内存里看不到这个Handle,它已经leak。(这种也算在GCHandle里吧)。

回头我们接着说他自己没被其他任何对象所引用,自己就是个根,但是GC却不搭理它,为何?那就是他在GCHandle里,?
而且在FinalizeQueue里也有它的踪影:
??下面就来解释下什么才可以在FinalizeQueue里出现呢?答案就是有身份的人,很有身份的人,享受特殊待遇的哦!
啥身份,就是自身实现拉析构函数。
啥待遇,就是GC两次才有可能把他们部分清理掉!为啥部分,是我们不知道windows到底何时去把所有的清理掉(赖皮阿)
具体原理大家可以看.net框架去,我这里不多说。?

说到此,也就找到我们当初30个彪形大汉为啥赖着不走的原因拉,是在0代的第一次GC时候,他们被放进FinalizeQueue,等着第二次GC他们部分才会从内存堆上消亡。
为证明我们的观点,我们可以修改程序为 :

?再用windbg查看线程时则为:

Taheta 标签: Thread,ThreadPool,windbg<script type="text/javascript">if ($ != jQuery) {$ = jQuery.noConflict();}var isLogined = false;var cb_blogId = 14015;var cb_entryId = 1370703;var cb_blogApp = "overred";var cb_blogUserGuid = "3c43360b-63cf-dd11-9e4d-001cf0cd104b";var cb_entryCreatedDate = '2009/1/6 22:41:00';</script>分类: ③ 你不常用的c#系列, ① NET Framework 标签: Thread, ThreadPool绿色通道:好文要顶关注我收藏该文与我联系 <!--done-->

t.Start();

}

Thread.Sleep(5000);//等待5秒
GC.Collect();

Thread.Sleep(5000);//等待5秒
GC.Collect();

Console.Read();

}
 回复 引用 查看 ?? #6楼2009-01-07 08:23 | S.Sams?????? --引用--------------------------------------------------
-tian-: 谢谢楼主的文章,正需要这样的文章呢。
--------------------
me to!
 回复 引用 查看 ?? #7楼2009-01-07 08:39 | 非空?????? 死线程还能唤醒吗?
 回复 引用 查看 ?? #8楼2009-01-07 08:52 | airwolf2026?????? 哇.非常感谢楼主这样的文章哈.
俺也很想了解这些底层的东西.但是限于时间等...(其实是懒,(*^__^*) 嘻嘻……)

现在总算明白为啥用线程池里面的比自己直接New Thread好了.嘎嘎
 回复 引用 查看 ?? #9楼2009-01-07 08:55 | 鳞?????? 学习了.虽然有些地方看不太懂.
 回复 引用 查看 ?? #10楼2009-01-07 08:57 | airwolf2026?????? 对啦,曾经在测试一个异步TCP程序的时候(一个和终端通讯的程序,就一条协议),整个异步方法里面加了个Lock,在异步方法里面出bug,弹出了一个Messagebox.结果第二天来看,发现这个程序耗了1G多内存....再看原因,既然它占用1k多的线程....
 回复 引用 查看 ?? #11楼2009-01-07 09:09 | Kevin-moon?????? 够深入!
最近正在研究内存这个东东 文章很不错
 回复 引用 查看 ?? #12楼2009-01-07 09:37 | winzheng?????? 深刻,顶。
 回复 引用 查看 ?? #13楼[楼主]2009-01-07 09:51 | overred?????? 谢谢各位
@eaglet
Sleep后GC清理FinalizeQueue线程开始启动,所以deadthread会根据你sleep的长短而数量不同
谢谢

@非空
这个例子里的线程不会唤醒拉。
因为内核对象中的context挂起计数已经大于0,当windows每隔大概 20ms(线程优先级度相同)扫一次,发现这些都不需要调度,不会分配任何cpu时间给他们。
 回复 引用 查看 ?? #14楼[楼主]2009-01-07 09:57 | overred?????? @airwolf2026
异步TCP的时候可以直接使用IOCP,这玩意据说是ms windows开发组搞拉很长时间想出的一个东东。
给你推荐几篇文章参考:
IOCP Thread Pooling in C#
地址:
http://www.devarticles.com/c/a/C-Sharp/IOCP-Thread-Pooling-in-C-sharp-Part-I/

http://www.devarticles.com/c/a/C-Sharp/IOCP-Thread-Pooling-in-C-sharp-Part-II/


 回复 引用 查看 ?? #15楼2009-01-07 10:09 | TerryLee?????? 不错的文章,支持overred:)

PS:现在回北京了吗?
 回复 引用 查看 ?? #16楼[楼主]2009-01-07 10:11 | overred?????? @TerryLee
嘻嘻。。。回拉
谢谢支持
 回复 引用 查看 ?? #17楼2009-01-07 12:36 | Angel Lucifer?????? 我来唱下反调。这篇文章的出发点有点莫名其妙。

ThreadPool 本身正是为了减少线程使用数量,避免过多上下文切换才设计出来的。内存占用肯定会比新建大幅数量的线程少的多。
这在 C++ 世界几乎是常识。凡是显式内存管理的编程语言,池化技巧是必备技能。我们在 .NET Framework 也可以多处看到此类技巧的应用。

所以我说这两个拿来比较有点莫名其妙。

PS : 如果想要更清楚的看到 GC 回收资源。可以在 GC.Collect() 后紧跟着调用 GC.WaitForPendingFinalizers() 方法。
 回复 引用 查看 ?? #18楼[楼主]2009-01-07 12:41 | overred?????? @Angel Lucifer
首先谢谢你的观点
你说的对

我就是对内存中的他俩对象的分布出发。。。
当我们在使用这俩东东的时候,内存中发生拉什么变化
比如我在使用Thread的时候为啥有上千个不会GC掉,而且占内存
对于这个相信windows核心编程讲的更明白。。。。

诸如 GC.Collect() 和GC.WaitForPendingFinalizers() 等方法在我们的编程中不应该作为一个方法使用(除非迫不得已),不然clr的GC机制不是浪费拉

呵呵
这不是反调,是在交流观点,文中有不对之处,还望斧正那。。。
thx

 回复 引用 查看 ?? #19楼[楼主]2009-01-07 12:56 | overred?????? @Angel Lucifer
补充一点
接调用GC.WaitForPendingFinalizers() 其实它应该就是在等clr的第二次GC
因为所有Thread的析构执行完毕他才会从FinalizeQueue里彻底移除

而WaitForPendingFinalizers正是挂起当前线程,等待第二次GC的时候,直到专门清理FinalizeQueue的线程对Queue彻底清理完毕,然后再返回。。。。这样世界就清净拉
Suspends the current thread until the thread processing the queue of finalizers has emptied that queue.
 回复 引用 查看 ?? #20楼2009-01-07 13:31 | Angel Lucifer?????? @overred
不过也应当注意一点,就是 .NET Framework 提供的线程池效率中庸。如果想要进一步提升程序性能,最好还是写一个专用线程池。 至于 GC ,《CLR via C#》讲的很清楚,很详细。
 回复 引用 查看 ?? #21楼[楼主]2009-01-07 14:53 | overred?????? @Angel Lucifer
校友好
.NET Framework 提供的线程池效率中庸的一大原因就是提供第三方保障,如内存和线程安全

其实IOCP不光用在IO上,用在Ap上一样很好。
,《CLR via C#》的作者老Jeffrey就很是IOCP的忠实拥护者
这点在他的核心编程里他都情不自禁的提起。。

 回复 引用 查看 ?? #22楼2009-01-07 15:46 | 毁于随?????? 认真的看了一遍,写的不错,深入浅出呀.
 回复 引用 查看 ?? #23楼[楼主]2009-01-07 17:18 | overred?????? @毁于随
谢谢

 回复 引用 查看 ?? #24楼2009-01-08 09:13 | airwolf2026?????? 多谢楼主给的链接.(*^__^*) 嘻嘻……
 回复 引用 查看 ?? #25楼2009-01-08 22:22 | 蛙蛙池塘?????? Smart Thread Pool 介绍
http://blog.csdn.net/greystar/archive/2007/08/31/1766363.aspx
 回复 引用 查看 ?? #26楼[楼主]2009-01-09 13:36 | overred?????? @蛙蛙池塘
蛤蟆好。。。。
 回复 引用 <a

读书人网 >C#

热点推荐