js中的數據類型可以分為基本類型和引用類型?;绢愋褪谴嬖跅却嬷械?,引用類型是存在堆內存中的,但是引用類型的引用還是存在棧內存中的。
基本類型:
1.聲明一個變量,多次賦值就會取取最后一個值
2.可以直接復制,復制之后的內容和原內容沒有什么聯系,類似于開辟了一個新的空間
3.不能添加屬性或者方法
引用類型
1.直接賦值給另一個變量以后相互之間的修改會互相影響對方,進而引出淺拷貝與深拷貝的問題
2.可以動態添加或刪除屬性/方法
棧
棧 是一種 先進后出 的數據結構,棧內存是內存中用于存放臨時變量的一片內存塊。當聲明一個基本變量時,它就會被存儲到棧內存中.而當其發生復制時,會把對應內存中的數據復制一份到新內存中
棧內存的特點:存取速度快,但不靈活,同時由于結構簡單,在變量使用完成后就可以將其釋放,內存回收容易實現。
堆
我們在訪問引用類型時,需要在棧內存中查找 對應的地址,在去堆內存中取得真正的值,訪問速度自然不及棧內存。
對引用類型進行復制時,應該把堆內存中的內容復制一遍,在將新地址賦值給新變量,這就涉及到深拷貝了
堆內存的特點:使用靈活,可以動態增加或刪除空間,但是存取比較慢
垃圾回收機制
原理
找出不使用的變量,釋放內存。
不使用垃圾回收機制會有什么后果
1.會消耗掉所有的可用內存(內存占用),造成系統崩潰
2.內存泄漏
什么時候觸發
該過程是周期性的,每隔一個固定的時間,就會自動運行程序。
如果分配的內存非常多,回收工作也會很艱巨,確定垃圾回收時間間隔就變成了值得思考的問題
基本思路
以一個函數中局部變量的正常生命周期為例。函數中的局部變量會在函數執行時存在,當函數執行完之后,此時該變量已經不在需要,占用的內存可以釋放,以供后者使用。所以垃圾回收機制需要跟蹤標記變量,并判定是否使用。如何標記未使用的變量也許有不同的實現方式。但是在瀏覽器里面的話有兩種常用的方式:標記清理和引用計數。
標記清理
垃圾回收程序運行的時候,會標記內存中存儲的所有變量。然后,它會將所有在上下文中的變量,以及被在上下文中的變量引用的變量的標記去掉。在此之后再被加上標記的變量就是待刪除的了,原因是任何在上下文中的變量都訪問不到它們了。隨后垃圾回收程序做一次內存清理,銷毀帶標記的所有值并收回它們的內存。
引用計數
思路是對每個值都記錄它被引用的次數。聲明變量并給它賦一個引用值時,這個值的引用數為1。如果同一個值又被賦給另一個變量,那么引用數加1。類似地,如果保存對該值引用的變量被其他 值給覆蓋了,那么引用數減1。當一個值的引用數為0時,就說明沒辦 法再訪問到這個值了,因此可以安全地收回其內存了。垃圾回收程序 下次運行的時候就會釋放引用數為0的值的內存。
該方法無法解決循環引用問題。如:A引用B,同時B引用A,相互應用。會導致內存泄漏。
內存泄露
是指程序上,動態的分配的堆內存,由于某種原因程序未釋放或無法釋放,造成系統的浪費,導致程序的運行速度減慢,甚至系統崩潰等嚴重后果。
JavaScript 內存管理
在內存中共用戶使用的內存空間分為3部分:
1.程序存儲區
2.靜態存儲區
3.動態存儲區
JavaScript 內存空間分配
棧:變量 基礎數據類型,值有固定大小(閉包除外)
堆:復雜的對象 引用數據類型的大小是不固定的,引用數據類型的值保持在堆內存的變量中
池:常量
注:JavaScript不允許直接訪問堆內存中的位置
實際上在操作對象的引用,而不是實際的對象
總結
- 離開作用域的值會被自動標記為可回收,然后在垃圾回收期間被刪除。
- 主流的垃圾回收算法是標記清理,即先給當前不使用的值加上標記,再回來回收它們的內存。
- 引用計數是另一種垃圾回收策略,需要記錄值被引用了多少次。
- 引用計數在代碼中存在循環引用時會出現問題。
- 解除變量的引用不僅可以消除循環引用,而且對垃圾回收也有幫助。
- 為促進內存回收,全局對象、全局對象的屬性和循環引用都應該在不需要時解除引用
垃圾回收機制觸發周期
以前的瀏覽器會按照固定的時間間隔周期性的執行,但這對性能上是比較影響的,因為瀏覽器會停止響應其他操作,而一次GC可能需要幾百毫秒才能完成。
現代瀏覽器基本都會在空閑時再去進行垃圾回收,而V8已經實現了并發標記,該技術可以讓 GC 掃描和標記對象時,同時允許 JS 運行。
所以很難具體回答什么時候會執行,這個因 js 引擎不同而策略不一樣。