iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 12
0
自我挑戰組

WebAssembly + Rust 的前端應用系列 第 12

[Day 12] Rust Ownership 所有權 (1)

大家好,今天要來介紹的是 Rust 的 ownership 老實說筆者在開始寫這篇之前沒有什麼信心,感覺沒有辦法很好的和各位解釋所以如果我有寫不對或是哪裏有疑問的同學可以跟我一起討論,那麼正文開始

什麼是 Ownership ?

有些程式語言會有自動的記憶體垃圾回收機制(garbage collection),在程式的生命週期會花費運算資源去找有哪些已經沒有在使用的資料並且把他釋放掉更甚者有些語言需要工程師手動在變數不用的時候把他釋放掉。而 Rust 採用方式就是 ownership,而 ownership 是定好的一些規則然後在編譯器編譯的時候所做的檢查機制,因此他不會在你程式的執行期間用到任何效能。

所以 ownership 是 Rust 一個很特別的觀念基本上筆者我也是第一次知道還有這樣的方式管理記憶體,因此學會 ownership 之後可以說是又多理解了一種在管理記憶體時的很好的策略。

The Stack and the Heap

但是在開始實作 ownership 之前我們必須先瞭解底層在處理記憶體時是如何控制的我們才能更好的理解為什麼 Rust 要這樣設計。

Stack

如果有讀過相關電腦科系的同學可能多少都有點印象中文就稱作"堆疊",而堆疊其實就是程式在編譯期間就已經知道的變數、函式等等,在系統執行的時候由系統控管用 LIFO(last in, first out) 後進先出的方式處理其記憶體的回收。下面用一張 wiki 的圖來說明,

https://ithelp.ithome.com.tw/upload/images/20190928/20119807N70xFhMmP2.png

Note: 堆疊只能處理在編譯時就已知位址和固定長度的資料。

筆記:筆者我後來去查為什麼系統層級的要用 stack 而不是 queues(FIFO frist in, first out),這邊給各位參考。

Because some things need to be done LIFO and some things FIFO.
For example, when a function call returns, it needs to return to the last item on the call stack, i.e., the function that called it. It would make no sense to return to the first item on the call-stack. Conversely, if you're serving requests, the next request you serve is the first one to enter the service queue. (It turns out that, actually, serving queues from the back can be more efficient but that has the obvious disadvantage that it risks starvation for things at the front of the queue and, in real-life queues of people, it just gives people a huge incentive to leave the queue and re-join.)

所以 stack 比較沒有太大的問題,而控制記憶體回收麻煩的地方在於 Heap。

Heap

假如我們有些資料是在執行期間才去計算出來的例如使用者鍵入的資訊等等,而這些資料由於在編譯期間還不知道他會佔用多少空間所以系統會配給他記憶體空間然後返回 pointer(指標)讓你對他做操作,所以當程式不需要使用的時候(在古老的語言例如 C 會需要人為判斷)才去把空間回收,而這個步驟就是很多工程師的痛處,因為若是處理得不好很容易導致很難回朔的 Bug 產生,甚至是導致系統掛掉。

官網舉了一個很好的例子幫助我們理解 heap,

Think of being seated at a restaurant. When you enter, you state the number of people in your group, and the staff finds an empty table that fits everyone and leads you there. If someone in your group comes late, they can ask where you’ve been seated to find you.

heap 的運作效能會比 stack 差,因為 heap 會需要系統去找到這筆資料但是 stack 不需要,詳細可以參考 wiki 這篇講 heap 是怎麼實作的,而且若是你的 heap 越大則消耗的運算資源就越多。

ownership 的目的就在於替你解決追蹤哪個部分的程式用了哪些在 heap 上的資料、最佳化在 heap 上重複的資料以及清除在 heap 上已經不用的資料,雖然當瞭解了 ownership 之後就不太需要太常想起 heap 和 stack 但是我們還是必須了解為什麼 Rust 設計 ownership 的原因。

總結

今天帶各位瞭解了 stack 和 heap 以及 ownership 的設計原因,明天就會帶各位開始了解 ownership 的規則還有同樣的練習一些範例程式,到時將用 String 的例子帶各位認識 ownership。

那麼我們明天見!

最後一樣有問題歡迎發問

/images/emoticon/emoticon07.gif

參考連結

ownership-in-rust-part-1

三種記憶體區間: global、stack、heap

Stack_(abstract_data_type)

why-do-we-use-stacks-and-not-queues-on-system-level


上一篇
[Day 11] Rust Control Flow 控制流程
下一篇
[Day 13] Rust Ownership 所有權 (2)
系列文
WebAssembly + Rust 的前端應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
DanSnow
iT邦好手 1 級 ‧ 2021-04-06 12:01:40

Ownership 我覺得它最主要不是為了管理變數的生命週期,雖然這邊也是有用到,但它主要應該是借由這樣的方式來確保不會有 data racing 的情況,另外 Rust 自動釋放 heap 的部份其實在這之前就有在 C++ 中出現了,這個概念叫 RAII ,意思是當物件初始化後,就用物件的 constructor 去取得資源的所有權,並在 destructure 時釋放,利用這樣的方式, C++ 的編譯器會自動插入 destructor 的執行就可以達到自動化的釋放資源了,而且這邊的資源包含但不限於 Heap 的使用,實際上還有像檔案的開關, Mutex 的取得與釋放都有用這樣的方式管理

另外 Heap 不代表它一定就是比較慢,因為就結果而言,它們都是一塊記憶體空間,但是 Heap 空間取得與釋放是需要額外的成本的,因為它有空間可能會跟其它的 thread 共用,因此可能會需要保證資料的多執行緒安全,這部份要看 Heap 的分配是用什麼方式實作的,像早期 Rust 會自帶 jemalloc 來分配 Heap ,它就有借由為每個 thread 先預先分配一個專用的空間的方式來加速小空間的取得與釋放

我要留言

立即登入留言