【JavaScript】數據結構與內存中的堆和棧

目錄

  • 前言
  • 一 堆棧
  • 二 堆棧與內存泄漏
  • 寫在最後

前言

電腦中一個很重要的部件是內存條,絕大多數時候咱們在操控一部分ram運行咱們的程序,因而就涉及到了堆棧的概念,鑑於老是記不住要查,寫一篇比較簡單的來記一下堆棧。瀏覽器

一 堆棧

堆棧是一個計算機專用術語,在數據結構裏它表明着兩種數據的操做方式,在內存維度裏表明着兩種不一樣的緩存方式和分配。緩存

1.1 數據結構中的堆棧

棧(stack): 相對來講你們比較熟悉一些,其數據的存取方式是先進後出,如同一個只有一個單元一層只有一戶的筒子樓倒着看(奇怪的比喻,-_-||主要是想說明空間與門牌號關係的感受),舉個例子,js中的全局下文棧在運行時是第一個進(push)棧的,在瀏覽器關閉時成爲最後一個出(pop)棧的。其餘的函數上下文也是存儲在棧中,可是通常都是即進(函數建立)即出(函數執行完畢)的,bash

堆(heap): 一種通過排序的樹形結構,一般用來實現優先隊列,有小頂堆和大頂堆兩種,能夠看做一個像樹同樣的書架,每本書的區域存放着必定特性的數據,能夠直接拿放。(沒具體寫過)數據結構

1.2 存儲空間中的堆棧(上下文與深淺拷貝)

棧區: 閉包

前面特地用上下文的存取舉了個棧結構的栗子,那麼js中除了上下文引用類型,別的類型的變量都存在哪裏呢?dom

首先能夠肯定的是基本類型都存放在棧區,該類型的數據存在該變量門牌號(地址)的房間裏(數據值)。因此當你在拷貝一個值給另外一個變量時,傳遞的是一個單純的值,不會再產生任何指向運算。而當你在聲明一個引用類型時,該變量所在的房間裏存放的數據實際是一個地址值,該地址指向了內存中的另外一塊區域——堆區。函數

堆區:性能

當引用類型被淺拷貝時,由於所分配的數據空間是同一塊,位於堆中的某一個位置。因此淺拷貝的數據值被所引用的引用類型變量所共同使用,一發則同全身。優化

而被深拷貝的時候,會根據執行從新分配一塊新的內存空間,兩個棧上的引用類型的變量指向運算後會指向堆中不一樣的地址空間。這個時候,你們各幹各的,雨各自無瓜。spa

這樣,在咱們想要深拷貝的場景中,咱們對引用類型拷貝時就不能使用直接賦值這種方式了,而是要從新分配一塊空間給被拷貝值。

舉個最簡單的例子:

function deepCopy(obj) { return JSON.parse(JSON.stringify(obj)); } // 最經常使用場景使用

固然,若是遇到無函數可調用時,那麼就須要手擼了,這裏只提與本文最核心一行:

if (isType(parent, 'xType')) {   child = xTypeInstance}複製代碼

二 堆棧與內存泄漏

2.1 內存泄漏

what

在某種場景下,對於分配的空間失去控制或者忘記釋放,這些空間就屬於泄漏掉的內存,在一些嚴重的遞歸或者是定時器場景中,內存泄漏會使瀏覽器內存佔用愈來愈高,影響性能。

why

爲何會產生內存泄漏,由於那部分空間不能被垃圾回收機制所回收。

在IE9之前,有兩種引用類型變量的垃圾回收策略,IE對於DOM對象會進行引用計數回收,而對於JS對象進行標記清除回收。

IE9之後瀏覽器對引用類型變量統一使用標記清除策略。

要去優化內存的時候,不用必定要記什麼dom引用js對象,js引用dom對象,或者是計時器對象未被清除,閉包產生泄漏什麼的,只須要理解標記清除的原理去分析就能夠了,全局變量所有被標記爲window引用,局部隨着所在函數上下文出棧而失去引用被即刻釋放,若是局部返回一個對象使仍然訪問到局部中的某些變量,則這些變量就沒有失去引用,天然就會繼續佔據內存空間。隨着一些場景中對這些返回的對象的需求結束,那麼咱們就須要釋放這些被綁在全局上的對象,則那些被對象所引用的變量的空間也會由於失去引用而被清除標記,隨後在瀏覽器的gc中被回收。

How to release 

將該變量的引用賦值爲null或者是將dom對象移除,在被多個對象引用時則都要處理纔會釋放空間。

寫在最後

雖然上面列舉了內存泄漏的緣由和處理方式,可是其實咱們應該注意的是去避免這些問題的出現,而有一些場景好比閉包產生的變量由於它是咱們刻意去引用的,因此並不屬於垃圾,不須要被回收。人爲回收前其實更要在寫代碼時就注意避免不規範的寫法以及不一樣場景變量是否屬於垃圾的搖擺。

相關文章
相關標籤/搜索