中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解決C#定時器保活機制引起的內存泄露問題

發布時間:2021-10-15 15:38:07 來源:億速云 閱讀:147 作者:柒染 欄目:編程語言

這篇文章將為大家詳細講解有關如何解決C#定時器保活機制引起的內存泄露問題,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

C# 中有三種定時器,System.Windows.Forms 中的定時器和 System.Timers.Timer 的工作方式是完全一樣的,所以,這里我們僅討論 System.Timers.Timer 和 System.Threading.Timer

1、定時器保活

先來看一個例子:

class Program{  static void Main(string[] args)  {    Start();    GC.Collect();    Read();  }  static void Start()  {    Foo f = new Foo();    System.Threading.Thread.Sleep(5_000);  }}public class Foo{  System.Timers.Timer _timer;  public Foo()  {    _timer = new System.Timers.Timer(1000);    _timer.Elapsed += timer_Elapsed;    _timer.Start();  }  private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)  {    WriteLine("System.Timers.Timer Elapsed.");  }    ~Foo()  {    WriteLine("---------- End ----------");  }}

運行結果如下:

System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.System.Timers.Timer Elapsed....

在 Start 方法結束后,Foo 實例已經失去了作用域,按理說應該被回收,但實際并沒有(因為析構函數沒有執行,所以肯定實例未被回收)。

這就是定時器的 保活機制,因為定時器需要執行 timer_Elapsed 方法,而該方法屬于 Foo 實例,所以 Foo 實例被保活了。

但多數時候這并不是我們想要的結果,這種結果導致的結果就是 內存泄露,解決方案是:先將定時器 Dispose。

public class Foo : IDisposable{  ...  public void Dispose()  {    _timer.Dispose();  }}

一個很好的準則是:如果類中的任何字段所賦的對象實現了IDisposable 接口,那么該類也應當實現 IDisposable 接口。

在這個例子中,不止 Dispose 方法,Stop 方法和設置 AutoReset = false,都能起到釋放對象的目的。但是如果在 Stop 方法之后又調用了 Start 方法,那么對象依然會被保活,即便 Stop 之后進行強制垃圾回收,也無法回收對象。

System.Timers.Timer System.Threading.Timer 的保活機制是類似的。

保活機制是由于定時器引用了實例中的方法,那么,如果定時器不引用實例中的方法呢?

2、不保活下 System.Timers.Timer 和 System.Threading.Timer 的差異

要消除定時器對實例方法的引用也很簡單,將 timer_Elapsed 方法改成 靜態 的就好了。(靜態方法屬于類而非實例。)

改成靜態方法后再次運行示例,結果如下:

System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.---------- End ----------System.Timers.Timer Elapsed.System.Timers.Timer Elapsed.System.Timers.Timer Elapsed....

Foo 實例是被銷毀了(析構函數已運行,打印出了 End),但定時器還在執行,這是為什么呢?

這是因為,.NET Framework 會確保 System.Timers.Timer 的存活,即便其所屬實例已經被銷毀回收。

如果改成 System.Threading.Timer,又會如何?

class Program{  static void Main(string[] args)  {    Start();    GC.Collect();    Read();  }  static void Start()  {    Foo2 f2 = new Foo2();    System.Threading.Thread.Sleep(5_000);  }}public class Foo2{  System.Threading.Timer _timer;  public Foo2()  {    _timer = new System.Threading.Timer(timerTick, null, 0, 1000);  }  static void timerTick(object state)  {    WriteLine("System.Threading.Timer Elapsed.");  }  ~Foo2()  {    WriteLine("---------- End ----------");  }}

注意,這里的 timerTick 方法是靜態的。運行結果如下:

System.Threading.Timer Elapsed.System.Threading.Timer Elapsed.System.Threading.Timer Elapsed.System.Threading.Timer Elapsed.System.Threading.Timer Elapsed.---------- End ----------

可見,隨著 Foo2 實例銷毀,_timer 也自動停止并銷毀了。

這是因為,.NET Framework 不會保存激活 System.Threading.Timer 的引用,而是直接引用回調委托。

關于如何解決C#定時器保活機制引起的內存泄露問題就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凤庆县| 怀柔区| 南通市| 宁阳县| 林芝县| 平凉市| 武宣县| 康定县| 京山县| 新昌县| 马鞍山市| 瑞昌市| 永清县| 沾益县| 凯里市| 平阳县| 襄城县| 盐亭县| 根河市| 东源县| 北流市| 星座| 泰宁县| 玛多县| 桦甸市| 抚顺县| 无锡市| 镇沅| 鄂尔多斯市| 龙陵县| 健康| 申扎县| 合山市| 神池县| 普兰店市| 拜城县| 札达县| 年辖:市辖区| 高雄市| 博爱县| 昌江|