一般的な JavaScript のメモリ リーク
メモリ リークとは
メモリ リークとは、プログラムが過失やエラーにより使用されなくなったメモリを解放できないことを指します。メモリ リークとは、メモリの物理的な消失を指すのではなく、アプリケーションがメモリの特定のセグメントを割り当てた後、設計上のエラーにより、解放される前にメモリのセグメントの制御を失い、メモリの無駄遣い。
メモリリークは通常、プログラムのソースコードにアクセスできるプログラマのみが分析できます。ただし、厳密には正確ではありませんが、メモリ使用量の望ましくない増加をメモリ リークと表現することに慣れている人がかなりいます。
————wikipedia
予期しないグローバル変数
JavaScript が宣言されていない変数を処理する方法: グローバル オブジェクトの変数への参照を作成します (つまり、変数ではなく、グローバル オブジェクトのプロパティです。削除で削除できます)。ブラウザーを使用している場合、グローバル オブジェクトはウィンドウ オブジェクトです。
宣言されていない変数が大量のデータをキャッシュしている場合、データはウィンドウが閉じられるか、ページが更新されるときにのみ解放されます。これにより、予期しないメモリ リークが発生する可能性があります。
<span style="font-size: 14px;">function foo(arg) {<br> bar = "this is a hidden global variable with a large of data";<br>}<br></span>
は次と同等です:
<span style="font-size: 14px;">function foo(arg) {<br> window.bar = "this is an explicit global variable with a large of data";<br>}<br></span>
さらに、これを通じて予期しないグローバル変数を作成します:
<span style="font-size: 14px;">function foo() {<br> this.variable = "potential accidental global";<br>}<br><br>// 当在全局作用域中调用foo函数,此时this指向的是全局对象(window),而不是'undefined'<br>foo();<br></span>
解決策:
JavaScript ファイルに「use strict」を追加して、strict モードをオンにします、上記の問題を効果的に回避できます。
<span style="font-size: 14px;">function foo(arg) {<br> "use strict" // 在foo函数作用域内开启严格模式<br> bar = "this is an explicit global variable with a large of data";// 报错:因为bar还没有被声明<br>}<br></span>
関数でグローバル変数を使用する必要がある場合は、次のコードに示すようにウィンドウ上で明示的に宣言できます:
<span style="font-size: 14px;">function foo(arg) {<br> window.bar = "this is a explicit global variable with a large of data";<br>}<br></span>
これは可読性が高いだけでなく、後のメンテナンスにも便利です
グローバル変数について言えば、大量のデータを一時的に保存するために使用されるグローバル変数に注意する必要があります。データを処理した後は、必ず null に設定するか、値を再割り当てしてください。グローバル変数はキャッシュとしてもよく使用されます。パフォーマンスを最適化するには、キャッシュのサイズに上限を設定するのが最善です。キャッシュは再利用できないため、キャッシュが多いほどメモリ消費量も多くなります。
console.log
console.log: Web 開発コンソールにメッセージを出力します。開発中のデバッグや分析によく使用されます。開発中にオブジェクト情報を出力する必要がある場合がありますが、公開時に console.log ステートメントを削除するのを忘れると、メモリ リークが発生する可能性があります。
console.log に渡されたオブジェクトはガベージ コレクションできません ♻️ これは、コードの実行後にオブジェクト情報を開発ツールで表示する必要があるためです。したがって、運用環境ではオブジェクトを console.log に記録しないことが最善です。
例----->demos/log.html
<span style="font-size: 14px;"><!DOCTYPE html><br><html lang="en"><br><br><head><br> <meta charset="UTF-8"><br> <meta name="viewport" content="width=device-width, initial-scale=1.0"><br> <meta http-equiv="X-UA-Compatible" content="ie=edge"><br> <title>Leaker</title><br></head><br><br><body><br> <input type="button" value="click"><br> <script><br> !function () {<br> function Leaker() {<br> this.init();<br> };<br> Leaker.prototype = {<br> init: function () {<br> this.name = (Array(100000)).join('*');<br> console.log("Leaking an object %o: %o", (new Date()), this);// this对象不能被回收<br> },<br><br> destroy: function () {<br> // do something....<br> }<br> };<br> document.querySelector('input').addEventListener('click', function () {<br> new Leaker();<br> }, false);<br> }()<br> </script><br></body><br><br></html><br></span>
ここではChromeのDevtools–>パフォーマンスと組み合わせて、分析を行います。手順は次のとおりです:
⚠️注) : ブラウザのプラグインが解析結果に影響を与えないように、非表示のウィンドウで解析作業を実行するのが最善です
[パフォーマンス]項目の記録を有効にします
CGを一度実行して、ベースライン基準線
ボタンを3回連続クリックして3つのLeakerオブジェクトを作成
CGを1回実行
記録を停止
それ[JS Heap] 行が最終レベルに戻っていないことがわかります。ベースライン参照行の位置には、明らかに回収されていないメモリがあります。コードを次のように変更すると、console.log("Leaking an object %o: %o", (new Date()), this); ステートメントを削除します。上記の手順を繰り返すと、分析結果は次のようになります:
比較分析結果から、console.log によって出力されたオブジェクトがガベージ コレクターによってリサイクルされないことがわかります。したがって、特に運用環境では、ページの全体的なパフォーマンスに影響を与える可能性があるため、ページ内の大きなオブジェクトを console.log に記録しないことをお勧めします。 console.log に加えて、console.dir、console.error、console.warn などにも同様の問題があります。これらの詳細には特別な注意が必要です。
closures(闭包)
当一个函数A返回一个内联函数B,即使函数A执行完,函数B也能访问函数A作用域内的变量,这就是一个闭包——————本质上闭包是将函数内部和外部连接起来的一座桥梁。
<span style="font-size: 14px;">function foo(message) {<br> function closure() {<br> console.log(message)<br> };<br> return closure;<br>}<br><br>// 使用<br>var bar = foo("hello closure!");<br>bar()// 返回 'hello closure!'<br></span>
在函数foo内创建的函数closure对象是不能被回收掉的,因为它被全局变量bar引用,处于一直可访问状态。通过执行bar()可以打印出hello closure!。如果想释放掉可以将bar = null即可。
由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多。
实例------>demos/closures.html
<span style="font-size: 14px;"><!DOCTYPE html><br><html lang="en"><br><br><head><br> <meta charset="UTF-8"><br> <meta name="viewport" content="width=device-width, initial-scale=1.0"><br> <meta http-equiv="X-UA-Compatible" content="ie=edge"><br> <title>Closure</title><br></head><br><br><body><br> <p>不断单击【click】按钮</p><br> <button id="click_button">Click</button><br> <script><br> function f() {<br> var str = Array(10000).join('#');<br> var foo = {<br> name: 'foo'<br> }<br> function unused() {<br> var message = 'it is only a test message';<br> str = 'unused: ' + str;<br> }<br> function getData() {<br> return 'data';<br> }<br> return getData;<br> }<br><br> var list = [];<br> <br> document.querySelector('#click_button').addEventListener('click', function () {<br> list.push(f());<br> }, false);<br> </script><br></body><br><br></html><br></span>
这里结合Chrome的Devtools->Memory工具进行分析,操作步骤如下:
⚠️注:最好在隐藏窗口中进行分析工作,避免浏览器插件影响分析结果
选中【Record allocation timeline】选项
执行一次CG
单击【start】按钮开始记录堆分析
连续单击【click】按钮十多次
停止记录堆分析
上图中蓝色柱形条表示随着时间新分配的内存。选中其中某条蓝色柱形条,过滤出对应新分配的对象:
查看对象的详细信息:
从图可知,在返回的闭包作用链(Scopes)中携带有它所在函数的作用域,作用域中还包含一个str字段。而str字段并没有在返回getData()中使用过。为什么会存在在作用域中,按理应该被GC回收掉, why
原因是在相同作用域内创建的多个内部函数对象是共享同一个变量对象(variable object)。如果创建的内部函数没有被其他对象引用,不管内部函数是否引用外部函数的变量和函数,在外部函数执行完,对应变量对象便会被销毁。反之,如果内部函数中存在有对外部函数变量或函数的访问(可以不是被引用的内部函数),并且存在某个或多个内部函数被其他对象引用,那么就会形成闭包,外部函数的变量对象就会存在于闭包函数的作用域链中。这样确保了闭包函数有权访问外部函数的所有变量和函数。了解了问题产生的原因,便可以对症下药了。对代码做如下修改:
<span style="font-size: 14px;"> function f() {<br> var str = Array(10000).join('#');<br> var foo = {<br> name: 'foo'<br> }<br> function unused() {<br> var message = 'it is only a test message';<br> // str = 'unused: ' + str; //删除该条语句<br> }<br> function getData() {<br> return 'data';<br> }<br> return getData;<br> }<br><br> var list = [];<br> <br> document.querySelector('#click_button').addEventListener('click', function () {<br> list.push(f());<br> }, false);<br></span>
getData()和unused()内部函数共享f函数对应的变量对象,因为unused()内部函数访问了f作用域内str变量,所以str字段存在于f变量对象中。加上getData()内部函数被返回,被其他对象引用,形成了闭包,因此对应的f变量对象存在于闭包函数的作用域链中。这里只要将函数unused中str = 'unused: ' + str;语句删除便可解决问题。
查看一下闭包信息:
DOM泄露
在JavaScript中,DOM操作是非常耗时的。因为JavaScript/ECMAScript引擎独立于渲染引擎,而DOM是位于渲染引擎,相互访问需要消耗一定的资源。如Chrome浏览器中DOM位于WebCore,而JavaScript/ECMAScript位于V8中。假如将JavaScript/ECMAScript、DOM分别想象成两座孤岛,两岛之间通过一座收费桥连接,过桥需要交纳一定“过桥费”。JavaScript/ECMAScript每次访问DOM时,都需要交纳“过桥费”。因此访问DOM次数越多,费用越高,页面性能就会受到很大影响。了解更多ℹ️
为了减少DOM访问次数,一般情况下,当需要多次访问同一个DOM方法或属性时,会将DOM引用缓存到一个局部变量中。但如果在执行某些删除、更新操作后,可能会忘记释放掉代码中对应的DOM引用,这样会造成DOM内存泄露。
实例------>demos/dom.html
<span style="font-size: 14px;"><!DOCTYPE html><br><html lang="en"><br><head><br> <meta charset="UTF-8"><br> <meta name="viewport" content="width=device-width, initial-scale=1.0"><br> <meta http-equiv="X-UA-Compatible" content="ie=edge"><br> <title>Dom-Leakage</title><br></head><br><body><br> <input type="button" value="remove" class="remove"><br> <input type="button" value="add" class="add"><br><br> <p class="container"><br> <pre class="wrapper">

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

株式分析に必須のツール: PHP および JS でローソク足チャートを描画する手順を学びます。特定のコード例が必要です。インターネットとテクノロジーの急速な発展に伴い、株式取引は多くの投資家にとって重要な方法の 1 つになりました。株価分析は投資家の意思決定の重要な部分であり、ローソク足チャートはテクニカル分析で広く使用されています。 PHP と JS を使用してローソク足チャートを描画する方法を学ぶと、投資家がより適切な意思決定を行うのに役立つ、より直感的な情報が得られます。ローソク足チャートとは、株価をローソク足の形で表示するテクニカルチャートです。株価を示しています

顔の検出および認識テクノロジーは、すでに比較的成熟しており、広く使用されているテクノロジーです。現在、最も広く使用されているインターネット アプリケーション言語は JS ですが、Web フロントエンドでの顔検出と認識の実装には、バックエンドの顔認識と比較して利点と欠点があります。利点としては、ネットワーク インタラクションの削減とリアルタイム認識により、ユーザーの待ち時間が大幅に短縮され、ユーザー エクスペリエンスが向上することが挙げられます。欠点としては、モデル サイズによって制限されるため、精度も制限されることが挙げられます。 js を使用して Web 上に顔検出を実装するにはどうすればよいですか? Web 上で顔認識を実装するには、JavaScript、HTML、CSS、WebRTC など、関連するプログラミング言語とテクノロジに精通している必要があります。同時に、関連するコンピューター ビジョンと人工知能テクノロジーを習得する必要もあります。 Web 側の設計により、次の点に注意してください。

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

インターネット金融の急速な発展に伴い、株式投資を選択する人がますます増えています。株式取引では、ローソク足チャートは一般的に使用されるテクニカル分析手法であり、株価の変化傾向を示し、投資家がより正確な意思決定を行うのに役立ちます。この記事では、PHP と JS の開発スキルを紹介し、株価ローソク足チャートの描画方法を読者に理解してもらい、具体的なコード例を示します。 1. 株のローソク足チャートを理解する 株のローソク足チャートの描き方を紹介する前に、まずローソク足チャートとは何かを理解する必要があります。ローソク足チャートは日本人が開発した

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは
