在穿插了內(nèi)存優(yōu)化之后为肮,我們回到內(nèi)存分配與跟蹤。接上次所說肤京,我想針對AAA游戲發(fā)布做必要的內(nèi)存分配和跟蹤颊艳,而不需大量時間來做內(nèi)存優(yōu)化。
方案需求
大多數(shù)AAA游戲有大量資源需要頻繁調(diào)入調(diào)出系統(tǒng)內(nèi)存和顯存忘分。在沙盒游戲中更嚴重棋枕,而大場景游戲(例如《NBA2015》)稍好些。不管怎樣妒峦,解決方案需要快速并提供正確的數(shù)據(jù)給所有的分配重斑。一個快速但不提供適當跟蹤工具的解決方案是不可取的,或提供了合適的跟蹤工具但速度很慢也是不行的舟山。兩項在衡量中都是很重要的绸狐。同時,所有分配必須通過它累盗,也就是說客戶端代碼或第三方庫不自己分配內(nèi)存寒矿,全局的new和delete操作應該override(重寫)。
跟蹤信息
解決方案必須提供相關(guān)的內(nèi)存跟蹤信息若债。其中符相,信息應包括所有的內(nèi)存占用,具體到某段內(nèi)存對應的分配地址蠢琳,包括所有內(nèi)存的啊终。任何內(nèi)存分配都需要有相關(guān)的跟蹤信息,什么時候分配的傲须,并可被程序員用來檢測問題蓝牲。
常規(guī)信息
提供的常規(guī)信息應該非常簡練。包括如下內(nèi)容:
分配字節(jié)數(shù)
分配次數(shù)
分配字節(jié)數(shù)峰值
分配次數(shù)峰值
內(nèi)存分配分組
就像有不同的小組或團隊一樣泰讽,說到游戲的不同功能時例衍,需要按組進行分配昔期。一些組用來渲染,游戲設置佛玄,UI硼一,音頻等等。不同分組有不同的內(nèi)存分配模式和需求梦抢。正因如此般贼,標準的內(nèi)存分組分配是個好主意,優(yōu)點如下:
優(yōu)化內(nèi)存分配設置奥吩。并不是所有分組都有同樣的分配需求哼蛆,所以最好是每組都可進行分配設置。也就是說比如:并不是所有組都需要互斥的分配器圈驼,并不是所有組都用同一個小塊分配器等等人芽。
預算跟蹤與強制執(zhí)行.每組分別擁有一定量RAM用來實現(xiàn)跟蹤,系統(tǒng)程序員可在不同組協(xié)調(diào)分配绩脆∮┨基本上,這就可以保證它們共享事務靴迫,所有內(nèi)存都在掌控之中惕味。
便于檢測崩潰問題。由于所有分配都有與組相對應的分配器設置玉锌,這就容易解決崩潰或在分配中出現(xiàn)的問題名挥。分組提供了良好的初始環(huán)境。
性能表現(xiàn)更優(yōu)主守。由于并不是所有的分組或分配都需要互斥禀倔,這些開銷可以避免。對于需要互斥分配器的組也會降低發(fā)生沖突的可能性参淫,因為并不只有一個互斥分配器(比如:全局分配器)加鎖救湖。在決定內(nèi)存分配方式時,要權(quán)衡絕對性能與內(nèi)存峰值二者涎才。
分配命名
為識別不同的分配鞋既,應該為所有的分配“命名”。名字表示誰需要內(nèi)存耍铜,也許可以強制命名規(guī)則邑闺,但為了跟蹤內(nèi)存分配,這些標簽應該是可以訪問的棕兼。為提高性能陡舅,這些標簽應該只在非發(fā)布版本上有效。
分配域
解決方案必須可以為每個線程的分配域的堆提供更多的上下文信息伴挚。它比使用堆棧的分配提供更好的上下文信息蹭沛,并且很容易獲取調(diào)用堆棧臂寝。在虛幻一個示例中,在UObject創(chuàng)建過程中創(chuàng)建域摊灭,這樣該Object相關(guān)的所有分配都在該域內(nèi)。所有非域內(nèi)的分配仍屬于全局域败徊。下面是作為葉節(jié)點分配域的示例和相關(guān)數(shù)據(jù):
Main Thread? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Pointer? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???Bytes? ?? ???Group
Global Scope
UGameEngine::Init
/Game/Maps/LandscapeMap.umap
AddToWorld
PersistentLevel
ConstructObject
FPhysXAllocator::allocate? ?? ???0x000000000b093fe0? ?? ???131720? ?? ???Physics
分配標志
分配可根據(jù)分配器不同的含義來提供可選標志帚呼。比如:
生命周期標志。提供關(guān)于分配的生命周期的提示皱蹦。當減少分配的內(nèi)存碎片時煤杀,分配器會更加智能。
分配清空標志沪哺。分配器就可以在返回之前清空已分配的內(nèi)存沈自。
性能
即便是帶可跟蹤功能的非發(fā)布版本,解決方案也必需達到可被接受的性能辜妓】萃荆可接受就意味著在有內(nèi)存跟蹤的情況下,每幀耗時不能超過50ms籍滴。若超過這個值酪夷,用戶就會盡量避免使用跟蹤功能了,這是滑坡孽惰,不得不在最糟糕的時候即版本發(fā)布時恢復晚岭。當然,性能損失和常規(guī)消耗應該在發(fā)布版本時降到零勋功。
分配分組
為實現(xiàn)可能的最佳分配方法而不必大大提高客戶端代碼復雜度坦报,為每組定義多個分配器就是順理成章的。這些分配器可被順序調(diào)用狂鞋,每個分配器都會成功返回分配的內(nèi)存片择。比如:常規(guī)組有三個分配器:
靜態(tài)小塊分配器(SSBA)。它是靜態(tài)分配小塊的分配器要销,不會增長构回,接受最大分配空間為256字節(jié)。
動態(tài)小塊分配器(DSBA)疏咐。它是動態(tài)分配小塊的分配器纤掸,可根據(jù)需要動態(tài)增長,最大空間為1024字節(jié)浑塞。
全局分配器(SA)借跪。系統(tǒng)標準分配器,可分配任意大小內(nèi)存酌壕。
若需要1032個字節(jié)的內(nèi)存掏愁,就會先嘗試SSBA歇由,DSBA,最好向SA請求內(nèi)存果港。若一個分配器就可以滿足需求沦泌,那就只用一個好了。比如:使用jemalloc(譯者注:開源的內(nèi)存分配庫)辛掠,它使用合理的加鎖機制可實現(xiàn)不同大小的內(nèi)存分配谢谦。
聯(lián)系方式:0755-81699111
課程網(wǎng)址: http://www.vrkuo.com/course/vr.html