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

溫馨提示×

溫馨提示×

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

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

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

發布時間:2021-06-24 14:29:32 來源:億速云 閱讀:151 作者:小新 欄目:編程語言

這篇文章主要介紹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

滨海县| 富蕴县| 高陵县| 庆安县| 烟台市| 东源县| 京山县| 竹山县| 白城市| 辰溪县| 静乐县| 云浮市| 分宜县| 台东县| 谷城县| 科技| 清远市| 肃南| 金阳县| 利辛县| 九寨沟县| 南开区| 万安县| 沅江市| 礼泉县| 尖扎县| 乌兰县| 铜川市| 梁河县| 宣城市| 清镇市| 信阳市| 高邑县| 青川县| 盐亭县| 大悟县| 秀山| 龙川县| 桃园县| 九寨沟县| 福建省|