この記事では、主に JS のガベージ コレクション メカニズムと一般的なメモリ リークの問題を解決する方法を紹介します。必要な友人に参考にしていただけるように共有します。クロージャのメモリリークの仕組みを理解したいと思ったときに、「JS上級プログラミング」のガベージコレクションの仕組みの解析を思い出しました。前はよく理解できませんでしたが、1年後に見返すと理解できるようになります。 , なので皆さんにもシェアしたくて書きました。気に入ったら、いいね/フォローしてサポートしてください。
メモリのライフサイクル:文字列、オブジェクトなどのサイズは固定されていないため、JS プログラムが文字列またはオブジェクトを作成するたびに、プログラムは
そのエンティティを保存するためにメモリを割り当てます割り当てられたメモリを使用して何かを実行します。
不要になったら解放して返す:
文字列とオブジェクトが不要になったら、それらが占有しているメモリを解放する必要があります。解放しないと、システム内の利用可能なメモリがすべて消費され、システムがクラッシュします。 . これが
ガベージコレクションメカニズムいわゆるメモリ リークとは、 を指します。過失またはエラーにより、プログラムが使用されなくなったメモリの解放に失敗し、メモリが無駄に消費されることです。
ガベージコレクションメカニズム:
C や C++ などの言語では、メモリを手動で管理する必要があり、これは多くの不必要な問題の原因でもあります。幸いなことに、js を記述するプロセスでは、メモリの割り当てとメモリのリサイクルは完全に自動的に管理されるため、この種のことを心配する必要はありません。ガベージ コレクターは、一定の時間間隔で定期的に使用されなくなった変数を見つけて、
それらが占有しているメモリを解放します使用されなくなった変数とは何ですか?
使用されなくなった変数は、関数の実行中にのみ存在し、他の参照 (クロージャ) が存在しない変数です。リサイクルとマークされます。 グローバル変数のライフサイクルは、ブラウザがページをアンロードするまで終了しません。つまり、
グローバル変数はガベージコレクションとして扱われません。
マークスイープ:現在採用されているガベージコレクション戦略動作原理:
ワークフロー:
ガベージコレクターは、操作中にメモリに保存されている
すべての変数をマークします。環境内の変数
と、環境内の変数によって参照される変数のタグを削除します。まだタグが付いている変数は、削除できる
変数とみなされます。最後に、ガベージ コレクターはメモリ クリアの最後のステップを実行し、マークされた値を破棄し、それらが占有しているメモリ領域を再利用します
。2008 年現在、IE、Chrome、Fireofx、Safari、Opera はすべてマークアンドスイープ ガベージ コレクション戦略を使用しています
が、ガベージ コレクションの間隔は異なります。循環参照: 各値の参照を追跡および記録するテクノロジー
古いバージョンのブラウザ (はい、また IE) では、IE9 より下の BOM および DOM オブジェクトは、 C++ を使用した COM オブジェクトの形式。 COM のガベージ コレクション メカニズムは参照カウント戦略を使用します。このメカニズムは循環参照が発生したときにメモリを解放できません。var element = document.getElementById('something'); var myObject = new Object(); myObject.element = element; // element属性指向dom element.someThing = myObject; // someThing回指myObject 出现循环引用(两个对象一直互相包含 一直存在计数)。
myObject.element = null; element.someThing = null;
排除
: IE9 は、BOM および DOM オブジェクトを実際の JS オブジェクトに変換し、このガベージ コレクション戦略の使用を回避します。 IE9 以下でよくあるメモリ リークの主な原因。IE7 には悪名高いパフォーマンスの問題があります。見てみましょう:
256 個の変数、4096 個のオブジェクト (または配列) リテラル、または 64KB の文字列、いずれかの重要な値に達すると、ガベージ コレクターが実行されます。ガベージ コレクション メカニズムはありますが、コードを記述するときに依然としてメモリ リークが発生する状況があります。これらの状況を理解し、プログラムを作成する際にそれを回避するように注意すれば、プログラムはより堅牢になります。
グローバル変数はガベージ コレクションとして扱われないと上で述べました
コーディング中に時々次のような状況に遭遇します:function foo() { this.bar2 = '默认绑定this指向全局' // 全局变量=> window.bar2 bar = '全局变量'; // 没有声明变量 实际上是全局变量=>window.bar } foo();
当我们使用默认绑定,this会指向全局,this.something
也会创建一个全局变量,这一点可能很多人没有注意到。
解决方法:在函数内使用严格模式or细心一点
function foo() { "use strict"; this.bar2 = "严格模式下this指向undefined"; bar = "报错"; } foo();
当然我们也可以手动释放全局变量的内存:
window.bar = undefined delete window.bar2
当不需要setInterval
或者setTimeout
时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。
var someResource = getData(); setInterval(function() { var node = document.getElementById('Node'); if(node) { node.innerHTML = JSON.stringify(someResource)); // 定时器也没有清除 } // node、someResource 存储了大量数据 无法回收 }, 1000);
解决方法: 在定时器完成工作的时候,手动清除定时器。
闭包可以维持函数内局部变量,使其得不到释放,造成内存泄漏。
function bindEvent() { var obj = document.createElement("XXX"); var unused = function () { console.log(obj,'闭包内引用obj obj不会被释放'); }; // obj = null; }
解决方法:手动解除引用,obj = null
。
就是IE9以下的循环引用问题,上文讲过了。
var refA = document.getElementById('refA'); document.body.removeChild(refA); // dom删除了 console.log(refA, "refA"); // 但是还存在引用 能console出整个p 没有被回收
不信的话,可以看下这个dom。
解决办法:refA = null;
过多的console,比如定时器的console会导致浏览器卡死。
解决:合理利用console,线上项目尽量少的使用console,当然如果你要发招聘除外。
记住一个原则:不用的东西,及时归还,毕竟你是'借的'嘛。
减少不必要的全局变量,使用严格模式避免意外创建全局变量。
在你使用完数据后,及时解除引用(闭包中的变量,dom引用,定时器清除)。
组织好你的逻辑,避免死循环等造成浏览器卡顿,崩溃的问题。
即使是1byte的内存,也叫内存泄漏,并不一定是导致浏览器崩溃、卡顿才能叫做内存泄漏。
一般是堆区内存泄漏,栈区不会泄漏。
基本类型的值存在内存中,被保存在栈内存中,引用类型的值是对象,保存在堆内存中。所以对象、数组之类的,才会发生内存泄漏。
使用chorme监控内存泄漏,可以看一下这篇文章
了解了内存泄漏的原因以及出现的情况,那么我们在编码过程中只要多加注意,就不会发生非常严重的内存泄漏问题。
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
原生JS基于window.scrollTo()封装垂直滚动动画工具函数
以上がJS 昇格におけるガベージ コレクション メカニズムと一般的なメモリ リークの問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。