小屋創作

日誌2019-07-28 01:51

[C#/Unity] 迴避踩坑 - C#的記憶體運作與陷阱

作者:HaoX@ミリシタ

使用Unity製作遊戲也好一陣子,

途中踩過不少坑都是對於Unity預設值與C#程式語言的設計上的不熟悉,

關於Unity預設值的部分,達哥在今年的TGDF上的簡報讓我獲益良多,大家都該去看看。

這次想探討的是關於C#程式語言的設計方面,

特別是相對於C/C++這些低階語言來說,C#/Java的記憶體分配像是一個巨大的黑盒子,

運作起來還蠻順利的,但是時不時就會像樂高一樣踩到腳(而且很痛),

這篇就來記錄一下自己學到的東西,順便討論裝箱(Boxing)跟C#的記憶體運作吧!




一、C#的記憶體分配
由於看到文章的朋友,可能不一定對程式語言的一些處理非常孰悉,

所以在這邊先簡單整理關於C#記憶體分配的一些規則。

對C#來說,一個Class分成三種類型:

1. Value Type 2. Reference Type 3. Pointer Type

其中第三項要開啟unsafe才能夠使用,而Unity的預設值是關閉的,所以可以先不理它。

前兩項Value Type跟Reference Type,在MSDN的官方說明上是這樣的:

Value types are either stack-allocated or allocated inline in a structure.
Reference types are heap-allocated

可以了解到,

對於Value Type來說,一般是存放在STACK段,做為區域變數使用。

對於Reference Type來說,一般是存放在HEAP段,由C#的Garbage Collection控管。

(當然這樣簡單的分類未必完全正確,因為他們其實存在一些實作細節的不同)

簡單來說:

Value Type就是一般常用的int, float, char, struct, enum這種簡單的資料型態,

他們在一般情況通常是區域變數,也就是用完就丟的,對記憶體的消耗也不會太大。

Reference Type就是利用class包裝起來的資料了,他們會被整包放到動態記憶體裡面,

如果不特別處理,就會持續占用記憶體,當相關的程式使用完這些變數,

C#就會利用Garbage Collection的方法,回收這些用不到的記憶體,

在Collect的當下會消耗較多CPU資源,甚至在手機上有可能會導致掉幀的情況,

所以我們一般會希望迴避這種動態記憶體的分配能夠有所節制,

也是前幾篇文章所提到的物件池存在的一部份原因。

二、萬惡的Boxing跟Unboxing
介紹完兩種C#的記憶體分配方式之後,再回頭討論標題的Boxing究竟是什麼意思吧。

在寫遊戲程式的時候,常常會遇到一種狀況:

「需要把現在的數值記錄下來,做為某種用途」

這種情況,我們常常會宣告一個class,像是下面這種存檔用的資訊:


在使用上,我們通常會寫成:


這種形式,此時原本存在區域變數的level跟health,就需要複製一份到動態變數區,

並且包裝成SaveFile的形式一直存在於動態變數區,直到它被使用完畢,被GC給回收去。

這樣從區域變數(Value Type)被打包到動態變數區段(HEAP段),就被稱為Boxing(裝箱)。

反過來從動態變數區段擷取成區域變數(Value Type)就被稱為Unboxing(拆箱)。

三、總結

其實Boxing跟Unboxing在寫程式的時候幾乎是難以完全避免的,

我們只要記得盡量少使用裝拆箱,以及在使用ArrayList, HashTable這種

一放進去就會被轉型成object type的自動裝箱結構時,要務必小心使用。

另外就是盡量在不忙碌的時候(打開UI選單、暫停遊戲、或讀取關卡時),

手動呼叫System.GC.Collect()進行手動GC,勢必可以稍微減少GC回收對效能造成的影響囉!

參考資料:
https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/types/boxing-and-unboxing
https://docs.microsoft.com/zh-tw/dotnet/standard/garbage-collection/fundamentals
https://docs.microsoft.com/zh-tw/dotnet/api/system.valuetype?view=netframework-4.8
http://dev.yesky.com/msdn/359/3486359.shtml

12

0

LINE 分享

相關創作

亂七八糟的_遊戲開發誌[23] Unity序列化 基本篇

Unity - UGUI篇 - 量條子物件跟隨(進度量條箭頭顯示)

[C#/Unity] 腳本分享 - 攝影機捕捉多角色

留言

開啟 APP

face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】