|
|
|
|
|
在前面我們介紹了幾個C#性能優(yōu)化技巧,你可以看出如下文章:
今天我再介紹一些C#技巧,這些方法可以使C#程序消耗更少的內(nèi)存,從而達到優(yōu)化性能的目的。
using塊比沒有using塊語句消耗更少的內(nèi)存
下面的例子可以證明 using
塊比沒有 using
塊語句消耗更少的內(nèi)存。
我們知道,如果我們實現(xiàn)一個 using
塊,代碼大小可能會更大,因為 using
塊在內(nèi)部會在 IL 代碼中創(chuàng)建一個 try ... catch
,但是一旦它在運行時在 IL 代碼中實現(xiàn),它就會有效地處理系統(tǒng)內(nèi)存。為了證明這一點,我編寫了一個簡單的程序,如下所示。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Globalization;
using System.Data.SqlClient;
namespace Test1
{
class Test
{
public void Test1()
{
StreamWriter wr = new StreamWriter(@"D:\text.txt");
}
public void Test2()
{
using (StreamWriter wr = new StreamWriter(@"D:\abc.txt"))
{
}
}
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.Test1();
t.Test2();
}
}
}
在輸出部分,我組合了三個輸出屏幕。
在分配圖中,我們看到 using
塊比沒有 using
塊消耗更少的資源,因為如果我們實現(xiàn) using
塊,程序可以有效地管理內(nèi)存。
通常高級別的方法,其速度越慢
通常,你使用的方法級別越高,它就越慢。我在這里發(fā)現(xiàn)的一個常見示例是,當處于代碼的繁忙部分(可能在被調(diào)用數(shù)百萬次的循環(huán)中)時使用 LINQ
。LINQ
非常適合快速表達可能需要大量代碼行的內(nèi)容,但大家經(jīng)常會把性能擱置一旁。
別誤會我的意思——LINQ 非常適合開發(fā)出可運行的應用程序。但是在代碼庫中以性能為中心的部分,可能會放棄太多。特別是因為將如此多的操作鏈接在一起非常容易。
我自己的具體示例涉及 .SelectMany().Distinct().Count()
,鑒于它被調(diào)用了數(shù)千萬次,它累積了大量的運行時間。我采用了另一種方法,將執(zhí)行時間減少了幾個數(shù)量級。
不要使用空析構函數(shù)
標題說明了一切——不要在你的類中添加空的析構函數(shù)。對于每個具有析構函數(shù)的類,都會將一個條目添加到 Finalize 隊列中。然后,垃圾收集器 (GC) 在調(diào)用析構函數(shù)的時候調(diào)用處理隊列。一個空的析構函數(shù)意味著這一切都是無用的。
請記住,正如我們已經(jīng)提到的,GC 執(zhí)行在性能方面并不便宜。不要不必要地為 GC 工作。
避免不必要的分配
在這里,我將重點關注一個技巧:避免不必要的分配。這意味著要避免這樣的事情:
List<Product> products = new List<Product>();
products = productRepo.All();
第一行創(chuàng)建了一個完全無用的列表實例,因為緊接著的下一行返回另一個實例并將其引用分配給變量。現(xiàn)在想象上面的兩行代碼在一個執(zhí)行數(shù)千次的循環(huán)中?
不要關注示例本身,而是關注一般建議:
C#/.NET 具有垃圾收集功能,該過程確定哪些對象當前已過時并將其刪除以釋放內(nèi)存空間。這意味著在 C# 中,與 C++ 等語言不同,你不必手動處理刪除不再有用的對象以聲明其內(nèi)存空間的問題。相反,垃圾收集器 (GC) 會處理所有這些,因此你不必這樣做。
問題是天下沒有免費的午餐,收集過程本身會導致性能損失,所以你真的不希望 GC 一直收集,那么你就應該盡量避免這種情況。
避免不必要的裝箱和拆箱
裝箱和拆箱——就像垃圾收集——在性能方面是昂貴的過程。因此,我們希望避免不必要地包含它們。
裝箱就像創(chuàng)建一個引用類型的框并在其中放入一個值類型的值。換句話說,它包括將值類型轉換為“對象”或此值類型實現(xiàn)的接口類型。拆箱正好相反——它打開盒子并從里面提取值類型。
然而,裝箱和拆箱本身就是昂貴的過程。除此之外,當裝箱一個值時,就會在堆上創(chuàng)建另一個對象,這會給 GC 帶來額外的壓力。
那么,如何避免裝箱和拆箱呢?
通常,可以通過避免 .NET(1.0 版)中早于泛型的舊 API 來實現(xiàn)這一點,因此必須依賴于使用對象類型。例如,更喜歡 System.Collections.Generic.List
之類的通用集合,而不是 System.Collections.ArrayList
之類的集合。
總結
本文介紹了一些C#技巧,這些方法可以使C#程序消耗更少的內(nèi)存,從而達到優(yōu)化性能的目的。
相關文章