五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Unity-了解自動內(nèi)存管理

2021-01-08 09:43 作者:unity_某某師_高錦錦  | 我要投稿

創(chuàng)建對象、字符串或數(shù)組時,用于存儲它的內(nèi)存是從稱為的中央池分配的。當(dāng)此項不再使用時,其先前占用的內(nèi)存可被回收并用于其他目的。在過去,通常由程序員通過適當(dāng)?shù)暮瘮?shù)調(diào)用顯式地分配和釋放這些堆內(nèi)存塊。如今,Unity 的 Mono 引擎等運(yùn)行時系統(tǒng)會自動為您管理內(nèi)存。自動內(nèi)存管理比顯式分配/釋放的做法需要更少的編碼工作,并且大大降低了內(nèi)存泄漏的可能性(即分配了內(nèi)存但后續(xù)從未釋放的情況)。

值和引用類型

調(diào)用某個函數(shù)時,其參數(shù)的值將復(fù)制到為該特定調(diào)用保留的內(nèi)存區(qū)域。只占幾個字節(jié)的數(shù)據(jù)類型可以非??焖俸洼p松地完成復(fù)制。但是,對象、字符串和數(shù)組通常要大得多,如果需要經(jīng)常復(fù)制這些類型的數(shù)據(jù),效率會非常低。幸運(yùn)的是,并不是非要這樣做;可從堆中分配大項的實(shí)際存儲空間,并使用小“指針”值來記住它的位置。此后,在參數(shù)傳遞期間只需要復(fù)制指針。只要運(yùn)行時系統(tǒng)能找到該指針?biāo)鶚?biāo)識的項,就可以根據(jù)需要頻繁使用該數(shù)據(jù)的同一個副本。

在參數(shù)傳遞期間直接存儲和復(fù)制的類型稱為值類型。這些類型包括整數(shù)、浮點(diǎn)數(shù)、布爾值和 Unity 的結(jié)構(gòu)類型(例如,__Color__ 和 __Vector3__)。在堆上分配后再通過指針訪問的類型稱為引用類型,因為在變量中存儲的值僅“引用”實(shí)際數(shù)據(jù)。引用類型的示例包括對象、字符串和數(shù)組。

分配和垃圾收集

內(nèi)存管理器跟蹤已知未使用的堆區(qū)域。當(dāng)請求新的內(nèi)存塊時(例如,當(dāng)實(shí)例化對象時),管理器選擇一個未使用的區(qū)域來分配內(nèi)存塊,然后從已知的未使用空間中移除分配的內(nèi)存。后續(xù)請求以相同的方式處理,直到?jīng)]有足夠大的可用區(qū)域來分配所需的塊大小。此時極不可能從堆中分配的所有內(nèi)存都仍在使用中。若要訪問堆上的引用項,前提是仍有引用變量可以定位到該項。如果對內(nèi)存塊的所有引用都消失(即,引用變量已被重新分配,或者引用變量是局部變量但現(xiàn)在已超出范圍),則可安全地重新分配其占用的內(nèi)存。

為確定哪些堆塊已不再使用,內(nèi)存管理器會搜索所有當(dāng)前處于活動狀態(tài)的引用變量,并將它們引用的塊標(biāo)記為“實(shí)時”。在搜索結(jié)束時,內(nèi)存管理器會認(rèn)為實(shí)時塊之間的任何空間都是空的并可用于后續(xù)分配。由于顯而易見的原因,定位和釋放未使用的內(nèi)存的過程稱為垃圾收集(或簡稱 GC)。

優(yōu)化

垃圾收集是自動完成的,對程序員來說不可見,但收集過程實(shí)際上在后臺需要耗費(fèi)大量 CPU 時間。如果使用得當(dāng),自動內(nèi)存管理通常在整體性能上能達(dá)到或超過手動分配。但是,程序員必須避免錯誤以免導(dǎo)致不必要的頻繁觸發(fā)垃圾回收器并在執(zhí)行中引起暫停。

有一些臭名昭著的算法雖然一眼看上去好像是無辜的,但可能成為 GC 的噩夢。重復(fù)的字符串連接便是一個典型的例子:

此處的關(guān)鍵細(xì)節(jié)是新的部分不會逐一添加到字符串。實(shí)際情況的是,每次循環(huán)時,line 變量的先前內(nèi)容變?yōu)樗劳鰻顟B(tài):分配的整個新字符串將包含原始部分加上末尾的新部分。由于字符串隨著 i 值的增加而變長,因此消耗的堆空間量也會增加,所以每次調(diào)用此函數(shù)時都很容易用掉數(shù)百個字節(jié)的空閑堆空間。如果需要將大量字符串連接在一起,那么 Mono 庫的?System.Text.StringBuilder?類將是更好的選擇。

但是,即使重復(fù)的連接也不會造成太大麻煩,除非頻繁調(diào)用,而在 Unity 中這通常意味著幀更新。類似以下腳本:

…在每次調(diào)用 Update 時都會分配新的字符串,并生成源源不斷的垃圾。通過僅在 score 發(fā)生變化時才更新 text,可避免大部分的垃圾:

另一個潛在問題是在函數(shù)返回數(shù)組值時出現(xiàn)的問題:

在新建包含值的數(shù)組時,這種類型的函數(shù)非常從容和方便。但是,如果重復(fù)調(diào)用這種函數(shù),則每次都會分配全新的內(nèi)存。由于數(shù)組可能非常大,因此空閑堆空間可能會迅速耗盡,導(dǎo)致頻繁進(jìn)行垃圾收集。避免此問題的一種方法是利用數(shù)組為引用類型這一特點(diǎn)。作為參數(shù)傳入該函數(shù)的數(shù)組可在該函數(shù)內(nèi)予以修改,且結(jié)果在函數(shù)返回后仍然保留。像上面這樣的函數(shù)通常可替換為如下所示的函數(shù):

此函數(shù)僅將數(shù)組的現(xiàn)有內(nèi)容替換為新值。雖然這需要在調(diào)用代碼中完成數(shù)組的初始分配(看起來有點(diǎn)不方便),但在調(diào)用該函數(shù)時不會產(chǎn)生任何新的垃圾。

禁用垃圾收集

如果使用的是 Mono 或 IL2CPP 腳本后端,則可以通過在運(yùn)行時禁用垃圾收集來避免垃圾收集期間的 CPU 使用率激增。禁用垃圾收集時,內(nèi)存使用量完全不會減少,因為垃圾回收器不會收集不再有任何引用的對象。事實(shí)上,禁用垃圾收集時,內(nèi)存使用量只會增加。為避免一段時間內(nèi)內(nèi)存使用量增加,請在管理內(nèi)存時慎重操作。理想情況下,在禁用垃圾回收器之前分配所有內(nèi)存,并在禁用垃圾回收器時避免進(jìn)行其他分配。

有關(guān)如何在運(yùn)行時啟用和禁用垃圾收集的更多詳細(xì)信息,請參閱?GarbageCollector?腳本 API 頁面。

請求進(jìn)行垃圾收集

如上所述,最好盡量避免內(nèi)存分配。但是,鑒于無法完全消除這些行為,可采用兩種主要策略來最小化這些行為對游戲運(yùn)行過程的干擾:

快速和頻繁進(jìn)行垃圾收集的小堆

這種策略通常最適合游戲運(yùn)行過程很長且主要關(guān)注幀率平滑性的游戲。像這樣的游戲通常會頻繁分配小塊,但這些塊的使用時間很短暫。在 iOS 上使用此策略時的典型堆大小約為 200KB,在 iPhone 3G 上的垃圾收集時間大約需要 5ms。如果堆大小增加到 1MB,則收集時間將大約需要 7ms。因此,有時,以定期的幀間隔請求進(jìn)行垃圾收集可能是有利的。這種情況下通常會使垃圾收集頻率高于嚴(yán)格意義上的要求,但是這些行為將得到快速處理,并且對游戲運(yùn)行過程的影響極?。?/p>

但是,應(yīng)謹(jǐn)慎使用此技術(shù)并檢查性能分析器的統(tǒng)計信息,以確保真正減少了游戲的垃圾收集時間。

慢速但不頻繁進(jìn)行垃圾收集的大堆

這種策略最適合內(nèi)存分配(因此垃圾收集)相對不頻繁并可在游戲運(yùn)行過程的暫停期間進(jìn)行處理的游戲。一種非常有用的方法是,盡可能增大堆的大小,但不至于因為系統(tǒng)內(nèi)存不足而導(dǎo)致操作系統(tǒng)終止您的應(yīng)用程序。但是,Mono 運(yùn)行時會盡可能避免自動擴(kuò)展堆。這種情況下,可通過在啟動期間預(yù)先分配一些占位空間來手動擴(kuò)展堆(即,實(shí)例化一個純粹為了影響內(nèi)存管理器而分配的“無用”對象):

一個足夠大的堆不應(yīng)在游戲運(yùn)行過程中配合進(jìn)行垃圾收集的暫停期間完全耗盡。發(fā)生此類暫停時,可顯式請求垃圾收集:

同樣,在使用此策略時應(yīng)謹(jǐn)慎,并注意性能分析器的統(tǒng)計信息,而不能僅僅期待其具有所需的效果。

可重用的對象池

在許多情況下,通過減少創(chuàng)建和銷毀的對象數(shù)量即可避免生成垃圾。游戲中存在某些類型的對象,例如飛彈,可能會多次反復(fù)遇到,但是只有少數(shù)對象會同時處于游戲中。在這種情況下,通??梢灾赜脤ο?,而不是銷毀舊對象并替換為新對象。

其他信息

內(nèi)存管理是一個微妙而復(fù)雜的主題,業(yè)界已投入了大量的學(xué)術(shù)努力。如果有興趣了解這一主題,memorymanagement.org?將是極好的資源,其中列出了大量出版物和在線文章。如需了解對象池的更多信息,請訪問?Wikipedia 頁面以及?Sourcemaking.com。


Unity-了解自動內(nèi)存管理的評論 (共 條)

分享到微博請遵守國家法律
隆昌县| 滁州市| 景德镇市| 淮北市| 金阳县| 天全县| 隆昌县| 土默特左旗| 萍乡市| 临湘市| 永定县| 玉环县| 沾化县| 洮南市| 交城县| 渝北区| 虹口区| 如皋市| 长垣县| 常州市| 周宁县| 岳阳县| 仁怀市| 长兴县| 彰武县| 贡嘎县| 福清市| 永吉县| 黎川县| 都安| 临武县| 乌拉特中旗| 平山县| 和平县| 朔州市| 溆浦县| 彰化市| 静安区| 法库县| 临颍县| 福泉市|