質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

960閲覧

メモリ上へのリソース発生・消失を検知したい

gvaslkjlie

総合スコア4

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/07/27 10:58

編集2020/07/27 10:59

###用語集
解説サイトA= https://logmi.jp/tech/articles/322067

抱えている問題・実現したいこと

html・css・javascriptでゲームを作っているが、
「このwebページは多くのメモリを使用しています」と警告が出る。
無視していると強制的にブラウザがページを再読み込みさせてしまうらしい。
ゲームプレイ途中にページが再読み込みされて処理がリセットされては困るので
メモリリークについて理解し、対策を取りたい。

前提

いろいろ解説サイトを読んだが、中でもゲームについて言及している
解説サイトAをメインで読んでいます。

###課題1:メモリ上への発生と消失のタイミングが不明
解説サイトAに載っている画像の、
https://img.logmi.jp/article_images/5kqEN4vopxWVUtJvnMNdf3.jpg
で「**chromeの検証ツール>memory>allocation instrumentation on timeline」**について

「画像やエフェクト、サウンドなどがいつのタイミングでメモリ上に発生して、消えていくかが追えるため、消えていないことがすぐわかります。」とあり、
画像発生検知テストを下記のように実施しました。

###試した時のソース

html

1<!DOCTYPE html> 2<html> 3 4<head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8</head> 9 10<body> 11 <div id="show">画像出す</div> 12 <script> 13 document.onclick = function () { 14 var img = document.createElement('img'); 15 img.src = 'test.jpg'; 16 img.alt = ''; 17 document.getElementById('show').appendChild(img); 18 } 19 </script> 20</body> 21 22</html>

上記ファイルをブラウザで開いた後、「**chromeの検証ツール>memory>allocation instrumentation on timeline>START」**して、記録を開始しました。そして#showをクリックしてtest.jpgを表示させました。そして記録を停止し、記録を見たが、多階層で大量に表示され、どこをクリックすれば情報が得られるか分からない為、いつメモリ上で発生したかも消えたかもわかりませんでした。

結果はconstructorとして表示されるので、「constructor img」で調べましたが分からず。Class filterで「image」と絞り込んで出てきた、HTMLImageElamentのconstructorを展開してsrcを1クリックしましたが、画像のパスは表示されず、なんの画像なのかは見つけられませんでした。

備考

以前
https://teratail.com/questions/280194
に質問しましたが、1つの実現したいこと・抱えている問題に対して課題が複数あったので、課題ごとに分けて質問する為、その理由を添えて削除依頼しました。削除依頼は運営にも受理され、現在は削除されています。運営に受理されたということで複数に分けて質問させていただきます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/07/27 11:00

単に「データが大きすぎる」(不要なものをメモリに配置しているわけではないけれど、それでもメモリが足りない)という可能性はありませんか?
gvaslkjlie

2020/07/27 11:25

ご回答ありがとうございます。確かにデータは大きいです。ゲームは最初に全データを読み込み、使い終わったDOMはjQueryのremoveでその都度消しています。となるとデータが一番重くなるのはブラウザで開いた直後なはずなのに、ゲームを開いた直後は何も警告が出ないのです。しばらくすると謎のタイミングで警告が出るので、メモリ状態をしらべて、警告が出るタイミングを把握したいのです。
AkitoshiManabe

2020/07/27 12:07

>「このwebページは多くのメモリを使用しています」と警告が出る これは、テストコードでも発生するのでしょうか。
gvaslkjlie

2020/07/27 12:12

AkitoshiManabe様 コメントありがとうございます。質問文に書いたコードでは発生していません。発生するコードは600行以上なのですが、メモリ発生検知するだけならもっとシンプルでいいと思い、簡素化したコードを載せています。
guest

回答2

0

ベストアンサー

メモリ上への発生と消失のタイミングが不明

検証ツールでは 総量の変化から目安となる内容の把握ができる程度ではないでしょうか。

個々のアセット(画像)を特定するには、フレームカウントや利用するシーンなど、ゲームのフレームワークの実装(本当にクリーンナップできているかなど)を確認すべきと思います。


ご質問のコードで実施されていない、画像の管理方法は気になりました。

  1. メモリ上にキャッシュするオブジェクト(HTMLImageElementをキーバリュー形式で管理)
  2. 実際に表示するオブジェクト(1. をクローンして描画)

たとえば、URL.createObjectURL( fileBlob ) を繰り返すと、メモリは新規に消費されるという挙動を確認したことがあり、別の質問で回答した CodePEN 画像のアップロードプレビュー では新規にメモリ消費されないよう、imageCache というオブジェクトに ファイル名:BlobURL を保持するコードにしています。

冒頭でも述べましたが、フレームワークの実装を疑うべきです。

多くのメモリを使用しています は ブラウザのヒープメモリに関わるエラーと思いますので、
Google検索 ブラウザ ヒープメモリも調査されてはいかがでしょうか。


追記

C言語でいう malloc free が不要となるのが ガベージコレクタです。

JavaScript上では malloc に類するコードは

  1. 各種宣言(サブリソースを読んだ後に渡される引数)
  2. コールスタックへの積み込みであり

free される条件はガベージコレクタ依存です。

  1. スコープを抜け、参照が切れている
  2. コールスタックから外れ、参照が切れている

ご質問のコード:

javascript

1 document.onclick = function () { 2 var img = document.createElement('img'); // メモリ確保 3 img.src = 'test.jpg'; // メモリ確保量増加 4 img.alt = ''; 5 document.getElementById('show').appendChild(img); 6 // => 文書木に配備され、参照が固定される(すぐには開放されない) 7 }

click を繰り返すと、ページがリロードされるまでにメモリリークする可能性があります。
適切に 文書木から削除(removeChild())して、ガベージコレクタに参照が切れたことを指示するコードがあれば状況も変わるはずです。

投稿2020/07/27 12:32

編集2020/08/02 06:45
AkitoshiManabe

総合スコア5432

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gvaslkjlie

2020/07/27 12:40

ご回答ありがとうございます。テストコードでは画像を「document.createElement('img')」で作っていますが、本番のコードでは最初からsrc属性を設定したimgタグがHTML上に存在し、使い終わったらjQueryのremove();で消すという管理方法にしています。フレームワークの実装を疑うべきとのことなので「jQuery メモリリーク」などで調べようと思います。「ブラウザ ヒープメモリ」も調査してみます。ありがとうございます。
AkitoshiManabe

2020/07/27 12:44

検索結果に「メモリの問題の解決 | Chrome DevTools | Google Developers」があり、こちらは、検証ツールの使い方について詳細が記されていますので、本回答よりも、そちらを確認してください。
gvaslkjlie

2020/07/27 12:51

ありがとうございます。確認いたします。
gvaslkjlie

2020/08/02 03:43

遅くなり申し訳ありません。 https://developers.google.com/web/tools/chrome-devtools/memory-problems?hl=ja (解説サイトB)の見出しごとに行ったことを下記に記します。 1:Chrome タスク マネージャによるメモリ使用量のリアルタイム監視 ↑数値が増えている場合、新規オブジェクトが作成されたか既存のオブジェクトが拡大しているとのことでしたが、原因となるオブジェクトの特定はできませんでした。 2:Timeline 記録によるメモリリークの表示 ↑カウンターペインはUIが変わったのか見つけられませんでしたのでSummaryタブを見ました。結果は下記です。 1 ms=Loading 250 ms=Scripting 760 ms=Rendering 222 ms=Painting 691 ms=System 31031 ms=Idle Idleは「JSやCSSなど、リソースをダウンロードしてからレスポンスが返ってくるまでの待ち時間」とのことで一番大きな割合を示していました。ただゲームなので画像や音素材を大量に使うのは避けられないのでIdleについてはどうしようもないかなと思いました。その他の項目は一秒もかかってないので追求していません。scriptingが250msなのでjsはメモリリークの原因ではなかったのかもしれません。(メモリリークで大事なのが秒数だと仮定した場合ですが) 3:ヒープ スナップショットによるデタッチされた DOM ツリーのメモリリークの検出 ↑解説サイトB記載の「Detached DOM tree」という項目が見当たらなかったので「Detached」で絞り込んだ結果の各項目第一階層をすべて押しましたが、黄色でハイライト表示されているノードがなく行き詰まりました。 4:Allocation Timeline による JS ヒープのメモリリークの特定 ↑青い縦線に絞り込んで結果を見たが、Constructorに500件以上出てきて断念。 5:関数ごとのメモリ割り当て状況の調査 ↑Heavyで並び替えると上位3つがjquery関連でしたので、maisumakun様の言う通りjquery以外のライブラリを使うことから検討し直さないといけないかもしれないです。
gvaslkjlie

2020/08/02 10:55 編集

追記ありがとうございます。クリックやドラッグなどのイベントが紐付けられている要素は役目を終えたらremoveし、イベントリスナーも使い終わったら消して様子を見ようと思います。
AkitoshiManabe

2020/08/02 21:23 編集

ゲームを作っている中でのご質問だったと思いますので、画像や音声ファイルを扱う要素にも着目してみるとよいかもしれません。JavaScriptプログラマの目に見えない場所でバイナリデータを保持するためのメモリ消費があるはずです(HTMLImageElementや、子要素に source 要素を持つことのできる要素は特に観察したほうが良さそう)。 https://developer.mozilla.org/ja/docs/Web/HTML/Element/source
guest

0

使い終わったDOMはjQueryのremoveでその都度消しています。

JavaScript内だけのオブジェクトと、DOMオブジェクトでは、かなり話が違ってきます

本当にDOMをきちんと消せているか確認してみましょう。ブラウザ内でDOMノードが残っているのであれば、インスペクタで比較的容易に確認できます。

投稿2020/07/27 11:29

maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/07/27 11:35

そこまでバカスカDOMを作り変える必要のある処理なら、jQueryではなく仮想DOM系のライブラリを使って作るほうが正解かもしれません。
gvaslkjlie

2020/07/27 12:16

ご回答ありがとうございます。検証ツールのhtmlタグが階層化して表示されるelementsタブをみながらゲームを走らせてみましたが、jqueryのremove();するタイミングでelementsタブからは消えています。react.jsを勉強していたこともあるのですが、とても難しく、使いやすいjqueryじゃダメな理由が分からなくてjqueryにしてしまいました。脱jqueryする理由を調べたこともあったのですが、出てくる用語の説明文の中に出てくる用語の意味を辿っていくうちに混乱してやめてしましました。
gvaslkjlie

2020/07/27 12:17

ゲームでは主にaddClassでcssのキーフレームアニメを実行するclassを付与して、animationendで完了を検知したら外し、別のclassを付与して、、、を繰り返しています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問