C# 雜記 Static 的宣告與釋放

莊創偉
Apr 29, 2021

一值以來對 Static 的印象都是一但宣告就會跟程式同生共死,所以必須慎用。直到某天看到新東家的舊Code用了滿天飛舞的 Static ,效能耗損確沒我預期中的嚴重。 於是有了這篇。

先附上MSDN:MSDN:Static

由於測試過程無趣所以直接先寫重點

  1. 靜態欄位(Static Field) 會在物件初次被建立時宣告,但是生命週期等同於執行序的生命週期,不會隨物件消滅而消滅(存放於Global)。
  2. 靜態類別於初次被叫用時建立生命週期等同於執行序的生命週期,不會隨物件消滅而消滅(存放於Global)。
  3. 靜態屬性與靜態方法每次叫用時都會重新執行。當中所包含的非靜態物件會於方法執行結束後釋放。執行效能上與非靜態方法並無差異。(但是非靜態有物件初始化的成本)
  4. 當一般類別中含有靜態屬性或欄位時相當於同時建立了一個靜態類別(當中只含靜態類)與一般類別(當中只含非靜態類)。
    4.1 如果作用域中有使用到靜態屬性,而該靜態類尚未建立則程式會在進入作用域時主動建立
    4.2 如果作用域中未使用到靜態屬性,則程式會在該類別第一次實作時先建立靜態類別

綜上所述我先前對於 Static 的了解是屬於靜態欄位,而靜態類別不知道是不是M社也覺得很容易令人混淆(還是只有我!!),所以有再拉一篇補充說明。

MSDN:靜態類別與靜態類別成員

以下是一些測試案例

可以看到程式一啟動一般類別的靜態欄位已經被宣告了,這是因為在readKey() 中有使用到A的靜態欄位,所以程式自動建構一個靜態類別A的關係。

相反的靜態類別的靜態欄位則要等到第一次被叫用後才會被系統建構。

兩者一樣都只會執行一次。

不同於靜態欄位,靜態屬性會重複執行。相對的靜態欄位所佔用的記憶體是可以回收的。

另外補充幾個重點:

  1. Alt +F2 可以打開效能觀測器,監看記憶體的用量
  2. 物件每次被賦予值都會佔用記憶體
static byte[] A = new byte[1024*1024*5]; A = new byte[1024*1024*5];

此時合計會佔去10mb的記憶體,且不會被釋放。靜態欄位賦值時要特別注意。

--

--

莊創偉

學海無涯。但是為了生計還是得下海的風塵男子