1. 程式人生 > >20181212——第四章 變數、作用域和記憶體問題

20181212——第四章 變數、作用域和記憶體問題

基本型別和引用型別
基本型別指的是簡單的資料段,而引用型別指的是那些可能由多個值構成的物件
基本型別是按值訪問,因為可以操作儲存在變數中的值
引用型別的值是儲存在記憶體中物件,與其他語言不同,javascript不允許直接訪問記憶體中的位置,也就是說不能直接操作物件的記憶體空間,在操作物件的時候,實際上是在操作物件的引用而不是實際的物件,

垃圾收集
JavaScript 具有自動垃圾收集機制,也就是說,執行環境會負責管理程式碼執行過程中使用的記憶體。
而在 C 和 C++之類的語言中,開發人員的一項基本任務就是手工跟蹤記憶體的使用情況,這是造成許多問
題的一個根源。在編寫 JavaScript 程式時,開發人員不用再關心記憶體使用問題,所需記憶體的分配以及無
用記憶體的回收完全實現了自動管理。這種垃圾收集機制的原理其實很簡單:找出那些不再繼續使用的變
量,然後釋放其佔用的記憶體。為此,垃圾收集器會按照固定的時間間隔(或程式碼執行中預定的收集時間),
週期性地執行這一操作。
下面我們來分析一下函式中區域性變數的正常生命週期。區域性變數只在函式執行的過程中存在。而在
這個過程中,會為區域性變數在棧(或堆)記憶體上分配相應的空間,以便儲存它們的值。然後在函式中使
用這些變數,直至函式執行結束。此時,區域性變數就沒有存在的必要了,因此可以釋放它們的記憶體以供
將來使用。在這種情況下,很容易判斷變數是否還有存在的必要;但並非所有情況下都這麼容易就能得
出結論。垃圾收集器必須跟蹤哪個變數有用哪個變數沒用,對於不再有用的變數打上標記,以備將來收
回其佔用的記憶體。用於標識無用變數的策略可能會因實現而異,但具體到瀏覽器中的實現,則通常有兩
個策略

標記清除
JavaScript 中最常用的垃圾收集方式是標記清除(mark-and-sweep)。當變數進入環境(例如,在函
數中宣告一個變數)時,就將這個變數標記為“進入環境”。從邏輯上講,永遠不能釋放進入環境的變數所佔用的記憶體,因為只要執行流進入相應的環境,就可能會用到它們。而當變數離開環境時,則將其
標記為“離開環境”。
可以使用任何方式來標記變數。比如,可以通過翻轉某個特殊的位來記錄一個變數何時進入環境,
或者使用一個“進入環境的”變數列表及一個“離開環境的”變數列表來跟蹤哪個變數發生了變化。說
到底,如何標記變數其實並不重要,關鍵在於採取什麼策略。
垃圾收集器在執行的時候會給儲存在記憶體中的所有變數都加上標記(當然,可以使用任何標記方
式)。然後,它會去掉環境中的變數以及被環境中的變數引用的變數的標記。而在此之後再被加上標記
的變數將被視為準備刪除的變數,原因是環境中的變數已經無法訪問到這些變量了。最後,垃圾收集器
完成記憶體清除工作,銷燬那些帶標記的值並回收它們所佔用的記憶體空間

引用計數
另一種不太常見的垃圾收集策略叫做引用計數(reference counting)。引用計數的含義是跟蹤記錄每
個值被引用的次數。當聲明瞭一個變數並將一個引用型別值賦給該變數時,則這個值的引用次數就是 1。
如果同一個值又被賦給另一個變數,則該值的引用次數加 1。相反,如果包含對這個值引用的變數又取
得了另外一個值,則這個值的引用次數減 1。當這個值的引用次數變成 0 時,則說明沒有辦法再訪問這
個值了,因而就可以將其佔用的記憶體空間回收回來。這樣,當垃圾收集器下次再執行時,它就會釋放那
些引用次數為零的值所佔用的記憶體。