Coding 應當是一輩子的事業,而不只僅是 30 歲的青春飯 本文已收錄 Github https://github.com/ponkans/F2E,歡迎 Star,持續更新前端
大爺: 看小夥子眉清目秀,不妨先跟我講講什麼是內存泄漏?node
小夥:(內心一陣暗喜)官方解釋是程序中己動態分配的堆內存因爲某種緣由程序未釋放或沒法釋放.git
但其本質其實就是一個,那就是應當回收的對象沒有被回收,變成了常駐在老生代中的對象。github
不少人說閉包會形成內存泄漏,其實說法不嚴謹,應該說是,閉包若是使用不當,容易引起內存泄漏,而不是閉包必定會形成內存泄漏。web
大爺:小夥子別激動,那你知道 Node.js 中形成內存泄漏的緣由通常有哪些嘛?redis
小夥:嗯,這個我也知道。能夠從緩存的角度來分析。算法
緩存在項目中是頗有做用的,由於一旦命中緩存,就能夠節約一次I/O的時間,而且訪問效率比I/O要高不少。npm
好比下面這種方式:緩存
let cache = {}
const setValue = function (value) { cache[key] = value } const getValue = function () { if (cache[key]) return cache[key] // 從其它渠道獲取 } 複製代碼
咱們都知道 V8 的垃圾回收機制是分新生代跟老生代的(若是不熟悉的小夥伴,能夠留言,後面出一篇 V8 垃圾回收機制)。安全
那麼一旦一個對象被當作緩存來使用,那就意味着這個對象會常駐老生代。
同時隨着你緩存對象的不斷增多,緩存對象也會愈來愈多,愈來愈大,垃圾回收在進行處理的時候,就會作不少無用功。
所以,上面的使用方式實際上存在一些問題:
所以,須要對上面的用法,接着改進,接着奏樂~
改進方式:FIFO-Cache
class Cache {
constructor (limit = 5) { this.limit = limit this.map = {} this.keys = [] } set (key,value) { let map = this.map let keys = this.keys if (!Object.prototype.hasOwnProperty.call(map,key)) { if (keys.length === this.limit) { // 先進先出的策略進行淘汰 delete map[keys.shift()] } keys.push(key) } map[key] = value } get (key) { return this.map[key] } } 複製代碼
實現方式很簡單,一旦key超過設定的限制值,就以隊列先進先出的方式進行淘汰。
大爺:小夥子,你上面這種方式只能針對一些比較簡單的場景,若是須要更加高效的緩存,是否能夠再優化?
小夥:這。。小夥欲言又止,始終仍是沒有說出那三個字~
LRU:最近被訪問的數據那麼它未來訪問的機率就大,緩存滿的時候,優先淘汰最無人問津者。相比FIFO,會更加精準跟高效
繼續優化,LRU-Cache
get (key) {
if (this.cache.has(key)) { let cache = this.cache const value = cache.get(key) cache.delete(key) cache.set(key, value) return value } return '其它渠道獲取' } set (key, value) { let cache = this.cache if (cache.has(key)) { cache.delete(key) } else if (cache.size === this.limit) { cache.delete(cache.keys().next().value) } cache.set(key, value) } } 複製代碼
以我的的經驗來看,在Node中,任何試圖拿內存來作緩存的行爲都應該被限制(被限制不是說徹底不能使用,可是須要謹慎使用)。
在特定場景下,仍是可使用的,畢竟走本地內存必定會比走網絡(好比Redis服務)更快。
所以,直接將內存做爲緩存存在不少的問題,須要開發者考慮的事情不少。
除了前面說的限制緩存大小,設置緩存淘汰等機制之外,還須要考慮進程間重複的緩存如何共享(畢竟進程之間沒法共享內存)。
因此,咱們能夠將緩存轉移到外部,不只能夠減小內存中緩存對象數量,讓垃圾回收更加高效,同時還實現了進程間共享緩存。
進程之間共享緩存是不少場景下都是頗有必要的,可參考《大前端進階 Node.js》系列 雙十一秒殺系統,裏面有提到這個問題
我的比較推薦Redis,各方面都作的很成熟,使用 Redis,上面提到的問題都不是問題了~
本文已收錄 Github https://github.com/ponkans/F2E,歡迎 Star,持續更新
寫這篇文章,是由於怪怪跟同事最近一塊兒討論 Node.js 內存泄漏的場景,因此計劃簡單寫一個小系列~
小結:
近期原創傳送門,biubiubiu:
喜歡的小夥伴加個關注,點個贊哦,感恩💕😊
微信搜索【接水怪】或掃描下面二維碼回覆」加羣「,我會拉你進技術交流羣。講真的,在這個羣,哪怕您不說話,光看聊天記錄也是一種成長。(阿里技術專家、敖丙做者、Java3y、蘑菇街資深前端、螞蟻金服安全專家、各路大牛都在)。
接水怪也會按期原創,按期跟小夥伴進行經驗交流或幫忙看簡歷。加關注,不迷路,有機會一塊兒跑個步🏃 ↓↓↓