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


本文完全獨立於前兩篇文章。如果你喜歡它們,我希望你也會喜歡這個。在上一篇文章中,我展示了哪種方法更快,並比較了代碼的執行速度。在本文中,我將展示不同代碼片段的內存消耗情況。為了顯示內存映射和分配圖,我使用了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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM