-
Unity內存分類:
Unity引擎開發的移動游戲,內存有三大部分:
- 程序代碼:包括unity引擎,使用的庫,和所寫的游戲代碼,在編譯后,得到的運行文件將會被加載到設備中執行,並占用一定內存。這部分內存實際上是沒有辦法去“管理”的,它們將在內存中從一開始到最后一直存在。優化只能減少使用的庫。
- 托管堆(Managed Heap):被Mono使用的一部分內存,對於Unity開發,其實充當了基本類庫的角色。托管堆用來存放類的實例(比如用new生成的列表,實例中的各種聲明的變量等)。“托管”的意思是Mono“應該”自動地改變堆的大小來適應你所需要的內存, 並且定時地使用垃圾回收(Garbage Collect)來釋放已經不需要的內存。關鍵在於,有時候你會忘記清除對已經不需要再使用的內存的引用, 從而導致Mono認為這塊內存一直有用,而無法回收。
- 本機堆(Native Heap):是Unity引擎進行申請和操作的地方,比如貼圖,音效,場景等。Unity使用了自己的一套內存管理機制來使這塊內存具有和托管堆類似的功能。基本理念是,如果在這個關卡里需要某個資源,那么在需要時就加載,之后在沒有任何引用時進行卸載。
Unity游戲在運行時的內存占用情況可以用下圖表示:
-
什么是Mono內存
對於目前絕大多數基於Unity引擎開發的項目而言,其托管堆內存是由Mono分配和管理的。“托管” 的本意是Mono可以自動地改變堆的大小來適應你所需要的內存,並且適時地調用垃圾回收(Garbage Collection)操作來釋放已經不需要的內存,從而降低開發人員在代碼內存管理方面的門檻。
目前絕大部分Unity游戲邏輯代碼所使用的語言為C#,C#代碼所占用的內存又稱為mono內存,這是因為Unity是通過mono來跨平台解析並運行C#代碼的,在Android系統上,游戲的lib目錄下存在的libmono.so文件,就是mono在Android系統上的實現。C#代碼通過mono解析執行,所需要的內存自然也是由mono來進行分配管理,下面就介紹一下mono的內存管理策略以及內存泄漏分析。
-
Mono內存管理策略
Mono通過垃圾回收機制(Garbage Collect,簡稱GC)對內存進行管理。Mono內存分為兩部分,已用內存(used)和堆內存(heap),已用內存指的是mono實際需要使用的內存,堆內存指的是mono向操作系統申請的內存,兩者的差值就是mono的空閑內存。當mono需要分配內存時,會先查看空閑內存是否足夠,如果足夠的話,直接在空閑內存中分配,否則mono會進行一次GC以釋放更多的空閑內存,如果GC之后仍然沒有足夠的空閑內存,則mono會向操作系統申請內存,並擴充堆內存,具體如下圖所示。
通過上文可知,GC的主要作用在於從已用內存中找出那些不再需要使用的內存,並進行釋放。Mono中的GC主要有以下幾個步驟:
1.停止所有需要mono內存分配的線程。
2.遍歷所有已用內存,找到那些不再需要使用的內存,並進行標記。
3.釋放被標記的內存到空閑內存。
4.重新開始被停止的線程。
除了空閑內存不足時mono會自動調用GC外,也可以在代碼中調用GC.Collect()手動進行GC,但是,GC本身是比較耗時的操作,而且由於GC會暫停那些需要mono內存分配的線程(C#代碼創建的線程和主線程),因此無論是否在主線程中調用,GC都會導致游戲一定程度的卡頓,需要謹慎處理。另外,GC釋放的內存只會留給mono使用,並不會交還給操作系統,因此mono堆內存是只增不減的。
參考:
https://blog.csdn.net/wetest_tencent/article/details/80124663