26


10

Chromeはメモリの解放に失敗し、ガベージコレクションは期待どおりに行われません(Mootools / MochaUIライブラリ)

背景:私は現在、MochaUIライブラリを使用するイントラネットサイトで作業しています(http://mochaui.org/demo/demo-virtual-desktop.html [仮想デスクトップデモ]から作業)。 Mootools 1.2.4およびMochaUI 0.9.7を使用しています。 「仮想デスクトップ」実装で開かれたウィンドウは、iframeを介してコンテンツをロードします。 読み込まれたページの一部は、CSSとスクリプトの点でかなり重いので、ユーザーがウィンドウを閉じたときにWindowオブジェクトが適切にガベージコレクションされることが重要です。 これは、表面上はライブラリによって処理されます(Firefoxを使用する場合は公平な仕事をします)。

*更新*最初に投稿された質問は、その後の編集/更新から非常に長くなりました。 タイトルはもう正確ではなかったので、私もそれを変更しました。 また、部分的な解決策については、以下の私の回答を参照してください。

重要なポイントは次のとおりです。

  1. * Chrome goofs up like like:*

    • ChromeはMochaUIウィンドウオブジェクトに割り当てられたメモリを解放できません 彼らが閉じているとき。 代わりに、Chromeのメモリ使用量は、ウィンドウがiframeコンテンツの読み込みを完了した後に到達したレベルで(文字通り)フリーズし、ページが更新されるまでメモリ使用量の下限を設定します。

    • プロセスで使用されるメモリは、その後も増加し続けます ウィンドウの開閉。 最終的に、ある種の上限に達し、メモリ使用量が急激に上昇するのではなく、急激に上昇するのではなく、急激に振動し始めます。

    • この問題は、問題のウィンドウがロードされているときに最も顕著です かなり多額の(メモリに関する)iframeコンテンツ。 すべてのテスト目的で使用しているウィンドウは、iframeに580 kbページ(キャッシュなし)をロードします。

  2. 奇妙なことに、予想されるガベージコレクションが行われます_does_、 いつ

    • ブラウザはその後最小化されます

    • 同じブラウザウィンドウで別のタブが開きます

    • メモリタイムラインが開発者ツールに記録されています。 (コメディ オプション)

    • この動作は、#1を解決するための可能なアプローチを示唆していますか?

2 Answer


6


これがWindowsでテストされたかどうかはわかりませんが、Windowsでウィンドウを最小化すると、すべてのデータがページファイルに移動することに注意してください。 再度ウィンドウを開くと、プログラムがメモリブロックにアクセスしようとしない限り、メモリブロックは戻されないため、ガベージはページファイルに残りますが、実際には収集されません。

自動化すると、プログラムの速度が低下するだけでなく、メモリの問題も解決しません。

詳細については、次のURLを参照してください


3


アップデート + MochaUIのclosingJobs関数に対する以下の変更は、以前ここに投稿したものよりも*大きな*改善です。 主な変更点は、windowEl.destroyメソッドがiframeをDOMから削除するときに発生するのではなく、srcプロパティを変更することでiframeのonunloadイベントが手動で呼び出されるようになったことです。 (http://o.dojotoolkit.org/forum/general/general-discussion/using-dojo-iframes-solving-memory-leak [こちら]からアイデアを入手してください)。

このコードを使用する場合は、既存のclosingJobs関数を削除して、このコードをその場所にコピーして貼り付けてください。 0.9.7と0.9.8の両方のMochaUI、およびMootools 1.2.4または1.3で動作するはずです。

'' '' '

closingJobs: function(windowEl){
    windowEl.setStyle('visibility', 'hidden');
    var instances = MUI.Windows.instances;
    var instance_id = windowEl.id
    var cleanup_delay = 50;

  /*
  Reset canvases with width/height = 0.
  This pretty reliably frees a few hundred Kb of
  memory in chrome.
  */
    instances[instance_id].canvasControlsEl.width = 0;
    instances[instance_id].canvasControlsEl.height = 0;
    instances[instance_id].canvasEl.width = 0;
    instances[instance_id].canvasEl.height = 0;

    if(instances[instance_id].options.loadMethod == 'iframe')
    {
 /*
 The following line determines how long to delay the execution of
 the windowEl.destroy function. The line below gives 10 milliseconds
 per DOM element in the iframe's document.
 You could probably do just as well with a hard-coded value.
 */
        cleanup_delay = instances[instance_id].iframeEl.contentDocument.getElementsByTagName("*").length * 10;

 /*
 Set the Browser property in the iframe's window to Internet Explorer.
 This causes Mootools to run its purge function, which iterates over
 all the iframe document's DOM elements, removing events/attributes etc.
 Assuming you have mootools included in the iframe content.
 */
        if(instances[instance_id].iframeEl.contentDocument.defaultView.MooTools)
        {
            if(instances[instance_id].iframeEl.contentDocument.defaultView.MooTools.version.contains("1.3"))
                instances[instance_id].iframeEl.contentDocument.defaultView.Browser.ie = true;
            else
                instances[instance_id].iframeEl.contentDocument.defaultView.Browser.Engine.trident = true;
        }

        instances[instance_id].iframeEl.src = "javascript:false";
    }

    MUI.cleanWindow.delay(cleanup_delay, null, windowEl);
},

cleanWindow: function(windowEl)
{
    var instances = MUI.Windows.instances;
    var instance_id = windowEl.id
    if (Browser.ie){
        windowEl.dispose();
    }
    else {
        windowEl.destroy();
    }
    instances[instance_id].fireEvent('onCloseComplete');

 /*
 Changed - Only execute getWindowWithHighestZindex() and focusWindow()
 functions if there will actually be open windows after the
 current one closes.
 */
    if (instances[instance_id].options.type != 'notification' && instances.__count__ > 1){
        var newFocus = MUI.getWindowWithHighestZindex();
        MUI.focusWindow(newFocus);
    }
    if (this.loadingWorkspace) this.windowUnload();
    if (MUI.Dock && $(MUI.options.dock) && instances[instance_id].options.type == 'window'){
        var currentButton = $(instances[instance_id].options.id + '_dockTab');
        if (currentButton != null){
            MUI.Dock.dockSortables.removeItems(currentButton).destroy();
            currentButton = null; //Is this necessary?
        }
        MUI.Desktop.setDesktopSize();
    }

    //Changed - moved this to the end of the function.
    delete instances[instance_id];
}