【JS檔案揭祕】第一集 記憶體洩漏與垃圾回收

陌上兮月發表於2019-07-30

程式的執行需要記憶體,對於一些需要持續執行很久的程式,尤其是伺服器程式,如果不及時釋放掉不再需要的記憶體,就會導致記憶體堆中的佔用持續走高,最終可能導致程式崩潰。

不再需要使用的記憶體,卻一直佔用著空間,得不到釋放,這就叫記憶體洩漏

在JS中,我們都知道,基本資料型別是存在棧(stack)中,而引用資料型別是存在堆(heap)中。存在棧中的資料,會被自動處理掉。但存在堆中的資料則不然。

JS引擎有個垃圾回收機制,可以幫助我們來清除不需要的資料。關鍵來了,我們怎麼告訴JS引擎這個我不再需要這個資料呢?

答案就是:切斷它的引用,讓它變成一座無法到達的島嶼

這就是所謂的“引用計數”。也就是說,我們對堆中的引用型別資料做一個遍歷,標記它們被引用的次數:

let a = {name:'zhang'};
let b = a;

let c = {name:'zhao'};
c = null;

在上面的這段程式碼中,{name:'zhang'}這個物件的引用次數為2,分別被變數a和變數b引用。{name:'zhao'}這個物件一開始被變數c引用,引用次數為1。後來c被重新賦值,{name:'zhao'}這個物件的引用突然被切斷,再也無法被訪問到了,自己變成了一個“孤島式資料”,其引用次數變成了零,被當成了垃圾。

 

而垃圾的宿命,就是被JS引擎回收。

我們來執行一下上述這段程式碼,每點選一次,就給obj存入1000個不同物件的引用,連續點選10s,停止30s。並把這個過程錄製下來。

怎麼錄?開啟chrome的performance即可錄製,看看這40s的記憶體堆(JS heap)的走勢。

 

 (結果是令人寒心的,堆記憶體佔用從15M左右飆到最高30M,且基本沒有什麼回落,居高不下)

 

現在我們把程式碼改一改,在末尾增加一句this.obj = []。用於清除本次操作產生的1000個引用。

按照同樣的手法,點選10s,停止30s,總共錄製40s。效果如下:

(可以看到中途最高飆到24.7M,但是垃圾回收在第5s和第10s都介入了一次,使得記憶體佔用大幅減少)

 

可以看到垃圾回收還是很有用的,同時也可以看到,垃圾回收並不是無時無刻都在進行,因為垃圾回收這個操作也有效能損耗,從我實測的結果來看,它是按照一定的時間間隔進行的。

 

相關文章