2012-10-08 67 views
0

我正在研究一種採用分配的對象併爲以後再分配它的分配算法。然而,回收對象的問題之一是,例如:使用後清理對象變量(pooling)c#

someObject obj = pool.alloc(); //gives me a new object if no previous allocations, If an allocation has been recycled, returns a previous allocation 
obj.someVariable = "foo"; 
pool.recycle(obj); 

上面的代碼將利用現有的分配,並保存它,這樣我就沒有分配任何額外的RAM的情況下,我是有另一個someObject。然而,下面創建一個問題:

someObject obj = pool.alloc(); //gives me the above allocation 
obj.otherVariable = "bar"; 
obj.dump(); 

結果,我會得到以下結果:

someVariable = foo 
    otherVariable = bar 

上述方法產生的問題。如果出於某種原因(或其他人)出於某種原因(而不是某個變量)在某個對象內部使用某種變量,那麼舊值可能會導致不必要的行爲。我探索了一下,看看是否有某種方法可以再次調用默認構造函數(壞主意),並且C#(謝天謝地)似乎不允許你這麼做。但是,我想知道是否有某種方法可以使用反射來做到這一點?另外,清除對象中的變量是否會破壞避免malloc(新)的目的?換句話說,如果我花時間清理變量,性能增益會變得最小?我試圖教我自己,所以任何批評和建議非常感謝!

+6

你有證據表明你需要這個池*嗎? –

+1

你可能不想這樣做。如果一個變量可以被輕易地重用,那麼編譯器/ JITter很可能會在你不知道的情況下做到這一點,如果不是的話,它可能會更加昂貴,並且更有可能不工作(並且也給程序員帶來更高的負擔告訴你的應用何時完成每個項目)。 – Servy

回答

1

下面是看着池的一種方法:

池是唯一真正必要的時候要重複使用一些複雜的設置工作,你可以通過檢索已經存在的對象避免。例如,最有名的對象池應用之一就是「數據庫連接」的形式。

對數據庫連接(DBConns)的池化工作,因爲1)DBConn可以由連接字符串平分識別; 2)DBConn需要大量的工作和時間來建立。通過匹配連接字符串來完成簡單的標識 - 如果兩個連接字符串相同,則它們建立的連接也應該是相同的。而且,一旦你有一個連接字符串,它可能需要幾百毫秒來查找服務器地址,打開一個套接字,驗證並建立連接。這意味着池可以很好地用於數據庫連接,因爲當連接被釋放時,下一次連接請求相同的連接字符串時可以重用它。

.NET運行時環境特別擅長快速分配對象並釋放它們,因此不存在內存問題。如果你擔心的是內存使用或分配速度,請不要;您無法通過自行清零內存來擊敗編譯器的性能。但是,如果您的對象有一些複雜而冗長的設置,可以通過從池中檢索現有對象來避免,則可以找到一些好處。

池的另一個很好的例子是視頻遊戲中的粒子系統。您必須創建數百個粒子,經歷一個生命週期並被銷燬,只有在舊粒子死亡後才能創建新粒子。一個典型的粒子系統將創建X個對象作爲一個數組,並且具有一個Reset()函數,該函數將一個死對象作爲新創建的粒子返回到原始位置。這個原理的原因又是因爲粒子可以被簡單地識別,並且設置工作(給圖形系統紋理,放置位置等)。

您的應用程序是否具有「微不足道的識別」功能和可避免的冗長設置過程?如果沒有,每次只分配新的對象 - 我會打賭你不會看到任何性能下降。

編輯:從性能的角度來看,讓我們來看看這個在這裏:

重置變量= O(N)賦值語句;使用反射可以顯着增加

實例化一個新對象=一個malloc調用,一個構造函數調用;複雜度級別取決於構造函數代碼和內存碎片。

使用反射重置變量可以工作,但您必須事先知道分配的O(N)比您的malloc和構造函數更快。對於數據庫連接,我知道條件滿足;但對你的游泳池來說這是真的嗎?

編輯:從您的評論下面,你可能確實發現一個情況下,合併是適當的。如果是這樣的話,我建議理想的方法是爲任何正在合併的類創建一個Reset()函數。嘗試創建一個定義了功能Reset()的接口IPoolable。然後,對於每個班級,定義Reset()函數,以便將所有關鍵變量歸零。因爲它編譯,所以不會產生反射開銷,並且可以維護動態代碼無法實現的特定於對象的優化。

對於泳池,請將泳池類定義爲MyPool<IPoolable>;那麼無論何時一個先前被回收的對象被檢索到,您可以在撥回給調用者之前調用Reset()

+0

現在它是一個巨大的ASPX應用程序,它從數據庫中獲取數據。很多這不是我的代碼,並從它的工作我發現,一切都是mallocing對象,通常是相同的類型一遍又一遍通常只是很快就丟棄它。少數用戶仍然可以,但過了一段時間後,這成爲一種負擔。另外,不,從使用視頻遊戲代碼開始,GC是一個非常糟糕的管理分配。 –

+0

對於分配太多對象的ASPX Web服務器,您可能希望開始緩存可能在未來某個位置重新請求的對象,而不是共享對象。雖然垃圾收集器已經很好地優化了,但避免不必要的分配/釋放會給你帶來最大的好處。 –

+0

我已經建立了一個改進了性能的緩存系統。試着更進一步,因爲將來這個應用程序將會變得更大。修復舊代碼的唯一方法是重寫它,但我沒有時間或意願去做。 –