NativeContainer(本地容器)
Unity Safety system(安全系統)數據拷貝的缺點之一,是將每個Job的計算結果也相互隔離,爲了解決這個限制,需要將Job結果存儲在一種共享內存類型的容器NativeContainer。
什麼是NativeContainer?
NativeContainer是一個對Unity本地內存進行相對安全的封裝並且接受管理的值類型。在使用Unity JobSystem時,NativeContainer允許job和主線程訪問共享內存,而不是通過內存拷貝。
有哪些NativeContainer可以用?
Unity提供了一個NativeContainer叫做NativeArray,你可以通過NativeSlice從特定位置開始操作固定長度操作NativeArray的數據子集。
注意:Unity ECS系統拓展了Unity.Collection命名空間下的NativeContainer類型:
* NativeList - 可變長度的NativeArray
* NativeHashMap - 鍵值對
* NativeMultiHashMap - 一鍵多值的哈希表
* NativeQueue - 先入先出列表
NativeContainer和Safety System之間的關係
SF是在所有NativeContainer類型中內置的,它追蹤了是誰在讀寫NativeContainer。
注意:
所有NativeContainer的安全類型檢查(如:越界檢查、釋放檢查、依賴檢查),都只在Editor和PlayMode下有效。
SF中的部分概念DisposeSentinel和AtomicSafetyHandle
* DisposeSentinel可能會在內存泄露後很久,纔會觸發並給出內存泄漏的錯誤日誌
* 在代碼中使用AtomicSafetyHandle移交NativeContainer的權限, 比如:如果兩個Job同時寫入NativeArray,SF在你調度Job的時候就會拋出清晰的異常日誌來告訴你怎麼去解決這個問題。因此你可以根據Job的依賴關係來調度,在第一個job完成nativeContainer的寫入之後,第二個Job可以安全的讀寫同一個NativeCondition,當然主線程讀寫的時候一樣需要嚴格限制。SF也允許多個並行Job的讀取同一個數據。
一個Job在默認情況下擁有NativeContainer的讀寫權限,這有可能會拖累性能表現,C# 的SF不允許一個Job在另一個Job寫入數據的時候擁有寫入權限,如果不需要寫入權限,可以在NativeContainer上添加[ReadOnly]標籤,比如:
[ReadOnly]
public NativeArray<int> input;
這樣其他Job就可以在當前job執行的時候,獲得NativeArray的只讀權限
注意:在訪問靜態數據的時候是不會有SF的安全保護的,靜態數據繞過了所有的SF,因此可能導致Unity崩潰。
NativeContainer 的分配
* Allocator.Temp 分配速度最快,試用於生命週期在一幀以內的job,你需要在方法結束之前調用Dispose方法
* Allocator.TempJob 分配速度比Temp慢,但是比Persistent快,適用於生命週期在四幀以內的Job,是線程安全的,如果你沒有手動調用Dispose方法,會在四幀之後輸出一條警告日誌,大部分小Job會採用這種類型
* Allocator.Persistent 分配速遞最慢,但是可以存在任意長的時間,必要的話可以貫穿整個應用的生命週期。本質上是malloc的直接封裝,其他更長的Job可以用這種類型,當然性能有壓力的時候,還是不要使用
如有錯誤,歡迎指正!