用Resharper的同學都知道,如果你寫了一個私有函數,這個函數沒有訪問類里面的其他參數和方法,那么它建議你標記這個方法為私有靜態方法,提示是這樣的:
值得這樣做嗎?看看微軟的建議:
After you mark the methods as static, the compiler will emit non-virtual call sites to these members. Emitting non-virtual call sites will prevent a check at runtime for each call that ensures that the current object pointer is non-null. This can result in a measurable performance gain for performance-sensitive code. In some cases, the failure to access the current object instance represents a correctness issue.
意思就是說,編譯器對標記為靜態的函數無需檢測this指針是否為空,有時候這樣的檢測會對性能敏感的應用產生影響。說的比較籠統,其實原因是對非靜態函數來說,都會默認傳遞第一個this參數,就是this地址,調用的時候會首先壓入棧;如果是靜態函數,this指針的入棧這一步就免了,IL就免了ldrag.0這一步:
CPU方面
而大家知道,傳遞一個額外的參數給函數需要一些開銷,CPU要把它放到寄存器,然后把它壓入線程棧(Thread Stack)等等。省了這一步自然性能有所提升。但其實和裝箱拆箱、算法、IO訪問、數據庫和網絡訪問等比起來簡直就是微乎其微,后幾項對性能的影響可能是十倍甚至百倍的。
內存方面
內存方面,大家知道函數和變量不同,變量的話私有的在線程棧(Thread Stack)中(調用函數前分配該內存),靜態的在全局堆(Heap)里面(在加載AppDomain的時候就分配)。函數在內存中通常是存放在代碼段(Code Segment),但在.NET中是在堆(Heap)里面,函數剛開始存在assembly中然后被映射到進程內存中,JIT編譯器把他們復制為native code並被執行,所以基本上函數在內存中是存在堆(Heap)里面。不是每個實例(instance)一份,只有一份。
該不該用?
如果你的私有函數沒有訪問類里面的其他參數和方法,又被頻繁調用,那就把他設為private static吧,沒有什么壞處哦。看看微軟的源碼里面,也是大量使用私有靜態方法:
最后提醒一句,public static的變量/方法/事件慎用,很容易引起內存泄露的問題。