谁动了我的timer?——C#的垃圾回收和调试
先来看如下的一段代码:
1 |
using System; |
我们在main函数中生成了一个timer,然后这个timer会每隔一秒输出一条记录,显示当前的时间。
如果运行这个程序(release模式),我们可以得到如下的输出:
这个程序看起来是运行正常的,可是真的是没有问题的吗?
我们简单的修改一下TimerCallback函数,强制调用一下GC,如下所示:
1 |
private static void TimerCallback(Object o) |
我们再次运行一下这个函数,得到了如下的输出:
我们可以看到,这次timer只被调用了一次!!!
这个时候大家应该能猜到原因了,我们的timer被垃圾回收了!!!
C#的垃圾回收采用了reference tracking的算法,大概的意思是说在执行垃圾回收时,所有的对象都默认认为是可以被回收的,然后遍历所有的roots(指向reference type的对象,包括类成员变量,静态变量,函数参数,函数局部变量),把这个root指向的对象标记成不能被回收的。
回到我们的代码,当我们强制调用GC.Collect()时,这个时候我们的timer t已经是一个没有被指向的对象了,于是垃圾回收就把t给回收了。这和C++的对象析构不太一样,C++的对象需要在出了作用域之后析构函数才会被调用到。
所以,即使我们没有显示的在这里调用GC.Collect(),但是我们不能确定什么时候CLR会调用GC,那个时候timer也就被回收了,总之,不能实现我们的意图。
再来个有意思的,如果我们把上面的程序改成debug模式再运行,发现我们的timer还是能够正常工作的,就是说还是能看到每隔一秒就输出一条记录。这又是为什么呢?
因为Visual Studio为了让debug更方便在debug模式下编译时延长了局部变量的生命周期。比如说,假设你在一个局部变量最后一次被使用之后打了断点,但是这个时候你在watch窗口已经看不到那个局部变量的值了(被垃圾回收了),那是不是很抓狂。所以debug的编译器就做了这个小手脚。
那如果要实现我们的初衷,就需要在Console.ReadLine之后还能保持一个对timer的引用,所以我们写了如下的代码:
1 |
public static void Main() |
很不幸,这在release下还是不行,因为编译器认为把一个对象置为null是没必要的,帮我们优化掉了!
所以正确的做法是:
1 |
public static void Main() |
这样就可以了。当然,我们也可以直接用using语句:
1 |
public static void Main() |
嗯,现在我们有了一个不会被垃圾回收掉的timer。希望对大家理解C#的垃圾回收有些帮助。
谁动了我的timer?——C#的垃圾回收和调试的更多相关文章
- Clr Via C#读书笔记---垃圾回收机制
#1 垃圾回收平台的基本工作原理: 访问一个资源所需的具体步骤: 1)调用IL指令newobj,为代表资源的类型分配内存.在C#中使用new操作符,编译器就会自动生成该指令.2)初始化内存,设置资源的 ...
- 重温CLR(十五) 托管堆和垃圾回收
本章要讨论托管应用程序如何构造新对象,托管堆如何控制这些对象的生存期,以及如何回收这些对象的内存.简单地说,本章要解释clr中的垃圾回收期是如何工作的,还要解释相关的性能问题.另外,本章讨论了如何设计 ...
- cir from c# 托管堆和垃圾回收
1,托管堆基础 调用IL的newobj 为资源分配内存 初始化内存,设置其初始状态并使资源可用.类型的实列构造器负责设置初始化状态 访问类型的成员来使用资源 摧毁状态进行清理 释放内存//垃圾回收期负 ...
- [CLR via C#]21. 自动内存管理(垃圾回收机制)
目录 理解垃圾回收平台的基本工作原理 垃圾回收算法 垃圾回收与调试 使用终结操作来释放本地资源 对托管资源使用终结操作 是什么导致Finalize方法被调用 终结操作揭秘 Dispose模式:强制对象 ...
- C#技术漫谈之垃圾回收机制(GC)
GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是 ...
- C#技术漫谈之垃圾回收机制(GC)(转)
GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是 ...
- 【转】【C#】C# 垃圾回收机制
摘要:今天我们漫谈C#中的垃圾回收机制,本文将从垃圾回收机制的原理讲起,希望对大家有所帮助. GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由 ...
- C#垃圾回收机制(GC)
GC的前世与今生 虽然本文是以.net作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是 ...
- C#技术------垃圾回收机制(GC)
GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是 ...
随机推荐
- C#入门经典(第五版)学习笔记(一)
---------------变量和表达式---------------赋值运算符:+=:-=:*=:/=:%=例如:i+=j 相当于 i=i+j i-=j 相当于 i=i-j以此类推 按位运算符:& ...
- ibatis集成Sqlite:小数据库也有大作用
作者:Vinkn 来自http://www.cnblogs.com/Vinkn/ 一.简介 Ibatis简介: Ibatis是一个类似于Hibernate的数据库ORM(对象关系映射,通俗点就是将数据 ...
- delegate 中的BeginInvoke和EndInvoke方法
开发语言:C#3.0 IDE:Visual Studio 2008 一.C#线程概述 在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能 ...
- QQ空间API接口
(以下内容可能会随着时间改变而改变!) 查看对方QQ空间的背景音乐 http://qzone-music.qq.com/fcg-bin/cgi_playlist_xml.fcg?json=0& ...
- ipconfig的C语言实现
首先,这篇文章实现了两种方法查询IP,实现截图如下: 第一种方法时调用系统命令,代码如下: #include <cstdlib> #include <iostream> usi ...
- Swift-MJ
1.声明变量 常量 声明变量:var age = 10 声明常量:let age = 10 (不加分号,除非多条语句写在同一行) 二进制前缀:0b(必须小写) 八进制前缀:0o 十六进制前缀:0x 2 ...
- 利用TraceSource写日志
利用TraceSource写日志 从微软推出第一个版本的.NET Framework的时候,就在“System.Diagnostics”命名空间中提供了Debug和Trace两个类帮助我们完成针对调试 ...
- IOS--UITextFiled的使用方法
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for ...
- 香港house of hello品牌包包是怎样被模仿呢?
今天,作为女性的朋友来说,house of hello包包可能对大家都不会陌生吧,特别是一些白领阶层的女性同胞们,这个品牌比较熟悉,现在,也有网友称,这个是恶搞包包.house of hello包包原 ...
- 批处理WMIC查看补丁情况
最近补丁比较多,需要看系统打了些啥,哪些没打的BAT: wmic qfe GET hotfixid > a.txt&(for %i in (KB3076321 KB3072604 KB3 ...