2011-08-16 24 views
2

例如在循環中,我應該重用單個類實例還是創建新實例?

Aclass myAclass = new Aclass(); 
    for(int i=0;i<n;i++) 
    { 
    myAclass.load(i); 
    myAclass.do(); 
    myAclass.clear() // clear the state of myAclass, rdy for next iteration. 
    } 

或者如果我嵌入`myAclass.load()入類的構造函數,並做某事喜歡:

for(int i=0;i<n;i++) 
    { 
     Aclass myAclass = new Aclass(i); 
     myAclass.do(); 
    } 

那麼哪種方式是更好的做法? 順便說一句,標題似乎不適合的內容,幫助我一個更合適的標題。

注:ACLASS的構造是微不足道的,負載()不是,清除()是

+1

取決於什麼是do()和什麼是clear() – sll

回答

2

有瑣碎 (因爲它觸發的load()的過程中,在第二個例子構造是不平凡的。)沒有辦法說明哪種方法在性能方面最好,這取決於班級的實施情況。

現在,作爲一般規則,您應該避免使用可變對象,因此重複使用該類的同一個實例來執行其他操作通常不是一個好主意。所以我贊成第二種方法。當然,如果類的初始化是一個昂貴的操作,第一種方法會更快...

至於內存使用情況,第二種方法會在內存中創建多個實例,但他們最終會被收集GC,所以它不應該是一個問題。唯一的缺點是它給GC帶來了更多的壓力,所以如果迭代次數很多,它可能會對性能產生負面影響。

+1

「你應該避免可變對象」。不可變對象有一些優點,函數式編程就是關於它們的,但我認爲這不是C#的「通用規則」。 – svick

1

出於性能方面它確實取決於有多少昂貴的構造Aclass類實例調用與Clear(),您可以測試是通過運行循環用10000迭代例如更好的性能和使用System.Diagnostics.Stopwatch測試,這是更好的性能。所以:

int n = 100000; 

    Stopwatch watch = Stopwatch.StartNew(); 

    Aclass myAclass = new Aclass(); 
    for(int i=0; i<n; i++) 
    { 
    myAclass.load(i); 
    myAclass.do(); 
    myAclass.clear() // clear the state of myAclass, rdy for next iteration. 
    } 
    watch.Stop(); 
    Console.WriteLine(watch.ElampsedMilliseconds); 
    watch.Reset(); 

    watch.Start(); 
    for(int i=0;i<n;i++) 
    { 
     Aclass myAclass = new Aclass(i); 
     myAclass.do(); 
    } 
    watch.Stop(); 

    Console.WriteLine(watch.ElampsedMilliseconds); 

編輯:爲一雙@馬克評論,我們應該首先調用功能,而沒有時間測量然後運行時間測試。所以:

AClass foo = new AClass(); 

foo.Load(0); 
foo.do(); 
foo.clear(); 

然後上面貼出的測試代碼「由int n = 100000;開始」。

+1

你應該運行這兩次,並忽略第一個結果,因爲第一個將支付JIT罰款,並且這樣的 –

+0

我很猶豫將這個答案添加到不提供問題的提問者,但不是_twice _ ..,只創建一個foo實例從測試開始時的'AClass'開始,所以'AClass foo = new AClass();'然後剩下的代碼.. –

+0

你至少想要其他的方法也被打亂;也許他們加載額外的組件或其他東西 –

3

通常,在C#中,垃圾收集器將爲您處理所有這些事情。

如果你想,當你用它做,明確處置的對象,確保它實現IDisposable,並在循環執行以下操作:

for (int i = 0; i < infinity; i ++) 
{ 
    using (MyClass myObject = new MyClass(i)) 
    { 
    myObject.DoWork(); 
    ... 
    } // The object will dispose here 
} 
+0

感謝TrueWill爲證明閱讀! (爲勝利拼寫ckecher!) – EtherDragon

0

在性能方面,第一個選項是最好的方式去。在第二個for循環中,每次迭代循環時,Aclass的一個新實例將被實例化並分配到堆上。您將在CLR將不得不垃圾收集的堆上留下這個類的許多實例。垃圾收集會減慢正在運行的程序的執行速度,因爲必須花費寶貴的CPU週期來釋放內存。

想想看,如果你的循環迭代1000次,它會留在堆1000個對象。即使每個對象是5MB甚至2MB,這都會大大減慢你的程序。去與第一。作爲一個方面說明,我更喜歡加載方法,而不是構造函數,因爲我覺得這是比較容易理解你與該類做。

1

很大程度上取決於Aclass的結構。

第一個選項通常會使用更少的內存,因爲您正在重新使用類實例。我說通常是因爲如果Aclass的狀態包含很多引用類型(字符串,其他類),那麼「清除」它(將這些引用設置爲null)仍然會將這些對象留在堆上以供垃圾收集器清理。由於清除對象所花的時間,它也可能會更慢(並且可能更容易出錯)。

第二種方式通常會更快(在.net中的分配真的很快),但通常會使用更多的內存。這是在.net,java和其他垃圾收集平臺中的常見模式,因爲垃圾收集器的意圖是模擬具有無限內存的環境(請參閱Raymond Chen's article。)

3

我要逆勢而爲,並建議做第二種方式(假設微不足道的構造)。垃圾收集器的成功來自於短暫的對象,

  1. 更容易推理,因爲你不重複使用相同的對象
  2. 爲對象的獨立性的結果共享循環迭代之間的狀態的第二種方式是簡單並行化的(假設沒有其他隱藏共享狀態)
相關問題