改進你的c#程式碼的5個技巧(三)

碼農譯站發表於2021-01-14

本文完全獨立於前兩篇文章。如果你喜歡它們,我希望你也會喜歡這個。在上一篇文章中,我展示了哪種方法更快,並比較了程式碼的執行速度。在本文中,我將展示不同程式碼片段的記憶體消耗情況。為了顯示記憶體對映和分配圖,我使用了CLR profiler 32位版本,和往常一樣,我在Windows平臺上使用了4GB RAM和Core i3 CPU。記憶體消耗或分配圖可能根據系統執行的程式而變化。因此,如果你得到一個不同的輸出或行為的程式碼,那麼請與我們分享你的經驗。

讓我們開始“改進c#程式碼的5個技巧:第3部分”的旅程。

StringBuilder消耗的記憶體比String少

在我的上一篇文章中,我已經展示了在長連線操作的場景中字串的速度有多慢。這裡我們會看到一個字串和StringBuilder的記憶體分配圖。讓我來演示一下。下面是我使用字串和StringBuilder進行相同操作的程式碼。

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  
{  
    public class Test1  
    {  
        string Name ;  
        public void Process()  
        {  
            Name = Name + "A";  
        }  
    }  
    public class Test2  
    {  
        StringBuilder sb = new StringBuilder();  
        public void Process()  
        {  
            sb.Append("A");  
        }  
    }  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            Test1 t = new Test1();  
            t.Process();   
            Test2 t1 = new Test2();  
            t1.Process();   
        }  
    }  
}  

這是程式碼執行時的記憶體分配圖。

這裡我們從main函式呼叫兩個函式Process();儘管它們都有相同的名稱,但它們屬於不同的類和Test1.Process處理字串資料,而Test2.Process()處理StringBuilder資料。在分配圖中,我們可以看到字串處理函式消耗了Main()函式94%的資源,而Test2類中處理StringBuilder的Process()只消耗了Main()函式的0.21%的資源。

因此,結論是“當你想多次連線字串時,總是使用StringBuilder”。

如果可能的話,使用靜態函式

是的,如果可能的話,嘗試實現一個靜態函式,因為靜態物件(函式和資料)不屬於特定類的任何物件。這是大家都有的。因此,如果不建立物件,就不存在記憶體消耗的問題。下面我將展示一個靜態函式和靜態類的示例。看一下IL程式碼。

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  
{  
    public static class mySclass  
    {  
        public static void Print()  
        {  
            Console.Write("Hello");  
        }  
    }  
    public class myNclass  
    {  
        public static void Print()  
        {  
            Console.Write("Hello");  
        }  
    }  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            for (int i = 0; i < 1000; i++)  
            {  
                mySclass.Print();  
                myNclass.Print();  
            }  
        }  
    }  
}  

IL程式碼在左手邊,在右手邊是由CLR分析器獲取的記憶體消耗類。由於空間消耗,我無法顯示CLR分析器的完整截圖。但是相信我,靜態類或函式沒有記憶體分配。

因此,結論是“如果可能,嘗試建立一個靜態函式並使用類名呼叫,而不是通過物件名呼叫通用函式”。

字串格式化VS字串連線

在第一點中,我展示了字串如何比StringBuilder消耗更多的資源。在這一點上,我將比較格式化輸出和字串連線。在第一個函式中,我使用了一個格式規範來列印格式化的輸出(基本上是連線一個字串)。在另一個函式中,我使用(+)操作符連線一個字串,如下所示:

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 Format()  
        {  
            int a = 100;  
            Console.WriteLine("{0}AND{1}", a, a);  
        }  
        public void Concatination()  
        {  
            int a = 100;  
            Console.WriteLine(a + "AND" +a );  
        }  
    }   
    class Program  
    {  
        static void Main(string[] args)  
        {  
            Test t = new Test();  
            t.Format();  
            t.Concatination();  
            Console.ReadLine();  
        }  
    }  
}  

在記憶體分配中我們會看到:

使用format列印字串的函式消耗了57%的資源,而簡單連線兩個字串的函式消耗了主函式的30%的資源。因此,我們可以清楚地看到,如果使用字串連線而不是輸出格式化,就可以節省系統資源。

空程式中哪個類消耗的資源最多?

首先,這一點並不推薦任何最佳實踐技術。我只是想說明,如果我們執行一個空程式(其中只有一個Main()函式),那麼分配了多少記憶體?下面是我的一個非常簡單的程式。

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;   
namespace Test1  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
        }  
    }
}  

是的,我沒有在這個程式裡寫任何東西。讓我們看看記憶體對映。

在這裡,我展示了與執行空程式場景相關的六個最耗費資源的類。可以清楚地看到,String類佔用了最多的資源(佔全部資源的25%)。現在提問。在一個我們從不使用字串的程式中,為什麼字串類消耗的資源最多?如果我們看一下這個程式的呼叫圖,我們會看到在main函式中有許多內部函式被呼叫,它們中的大多數都以字串作為引數,為了生成這些引數,CLR通常使用string類。如果你有不同的意見,請使用下面的評論框。

實現一個using塊來管理記憶體

始終實現一個using塊來管理資源是一個最佳實踐。實際上,我們可以證明使用block語句比不使用block語句消耗的記憶體更少。我們知道,如果我們實現一個using塊的塊程式碼大小可能會更大,因為using塊在內部在IL程式碼中建立了一個try catch,但一旦它在執行時在IL程式碼中實現,它就能有效地處理系統記憶體。為了演示這一點,我編寫了一個簡單的程式,如下所示:

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塊時消耗的資源更少,因為如果我們實現了using塊,程式可以有效地管理記憶體。

歡迎關注我的公眾號,如果你有喜歡的外文技術文章,可以通過公眾號留言推薦給我。

原文連結:https://www.c-sharpcorner.com/UploadFile/dacca2/5-tips-to-improve-your-C-Sharp-code-part-2/

相關文章