【问题标题】:Javascript force GC collection? / Forcefully free object?Javascript强制GC收集? / 强制释放对象?
【发布时间】:2010-06-13 22:42:22
【问题描述】:

我有一个 js 函数,用于使用音频接口播放任何给定的声音(为每个调用创建一个新实例)。

这工作得很好,直到大约第 32 次调用(有时更少)。此问题与 Audio 实例的发布直接相关。我知道这一点是因为我已经让 Chromium 中的 GC 有时间运行,它可以让我再次播放另外 32 种左右的声音。

这是我正在做的一个例子:

<html><head>
<script type="text/javascript">
function playSound(url) {
    var snd = new Audio(url);
    snd.play();
    snd = null;
}
</script>
</head>

<body>
<a href="#" onclick="playSound('blah.mp3');">Play sound</a>
</body></html>

我也有这个,它适用于少于 32 个 playSound 调用的页面:

var AudioPlayer = {
    cache: {},
    play: function(url) {
        if (!AudioPlayer.cache[url])
            AudioPlayer.cache[url] = new Audio(url);
        AudioPlayer.cache[url].play();
    }
};

但这不适用于我想做的事情(用其他内容(来自单独的文件)动态替换 div,这些内容有更多的声音 - 1. 内存使用量很容易飙升,2. 很多声音永远不会玩)。

我需要一种立即释放声音的方法。是否有可能做到这一点?我没有找到音频接口的免费/关闭/卸载方法。

页面将在本地查看,因此声音的持续加载根本不是一个重要因素(而且大多数声音都很短)。

【问题讨论】:

    标签: javascript garbage-collection


    【解决方案1】:

    我看到至少一个(或两个)缺陷:

    snd = new Audio(url);
    

    前面没有var,所以snd被分配给全局范围。这通常不是您想要的:它使全局名称空间变得混乱,如果另一个脚本(例如,扩展)偶然使用snd,事情就会一团糟。

    这也是为什么

    delete snd;
    

    不起作用:你不能delete global variables:

    当声明变量和函数时 成为变量对象的属性 — 任一激活对象(对于 功能代码),或全局对象(对于 全局代码),这些属性是 使用 DontDelete 属性创建。

    所以,使用

    var snd = new Audio(url);
    

    相反。顺便说一句,您不能强制 JavaScript 引擎进行垃圾回收。

    【讨论】:

    • 啊,那个。不久前我正在测试一些让我删除 var 的东西。它原本就在那里。编辑:更正。
    • @plash:好的,但我会在这里留下我的答案,因为它可能对其他用户有用。
    • 这不是真的!可以通过delete window.snd删除全局变量;
    • @DotNetWise:如果您没有通过属性赋值声明变量,则不会:如果您执行var foo = 1,foo 将获得DontDelete 属性;你不能用delete window.foo 删除它。但是,我不确定在没有var 语句的情况下全局声明的变量:快速测试表明您实际上可以 删除这些变量。也许这是 ES 5.1 中的新功能,最近没有检查。当我有更多时间时,我会进一步探讨这个特殊案例并让你知道。
    • 在最新的 chrome、IE10 和最新的 FF 中都不是这样。 xx = 1; 1 >> 删除window.xx true >> xx "'xx' 未定义"
    【解决方案2】:

    这不是一个详尽的答案,而是针对“有没有办法强制 chrome js 引擎进行垃圾收集?”的问题,a chromium.org guy replied:

    一般来说,不,设计使然。 出于测试目的,您可以通过一个标志 在命令行上启用 javascript 命令“window.gc()”强制 垃圾收集。

    --js-flags '--expose_gc'


    更新:但是,正如@plash 在下面的评论中指出的那样,此标志仅在调试版本中有效。

    【讨论】:

    • Greeaat。我必须开始使用脚本来为这个项目启动 Chromium(已经使用 --allow-file-access-from-files 以便我可以从本地文件系统打开文件)。编辑:我认为这是最后的手段。
    • @plash:请务必查看the post that I linked to,因为我引用的回复包含可能相关的更多信息。我没有亲自测试过。
    • @plash:太糟糕了...让我更新我的答案,仅供其他读者参考。
    • 该标志在发布版本中确实有效 (crbug.com/100875)。但我认为你传错了。试试:chrome --js-flags='--expose_gc'
    • 在 Ubuntu 中,有效的命令是 chromium-browser --js-flags='--expose_gc'
    【解决方案3】:

    只是删除并将其设置为 null 对我也不起作用,所以我做了一个解决方法。

    我让它同时为多个声音工作。要释放实例,每个声音都需要是一个对象标签。动态地将每个对象标签(声音)附加到一个 Div。要释放实例,请从 Div 中动态移除 Object Tag(声音)。

    我猜这是可行的,因为浏览器通常将每个标签实现为某种对象。因此,当我删除一个标签时,内部对象会被删除并释放与之关联的所有资源。

    <!--HTML: This will contains object sounds-->
    <Div id="sounds"></Div>
    
    //Javacript, using jQuery
    //Create and play an MP3
    var id_event = 1234; //Keep and incrementing a counter might do, I use an Event Id from my app.
    var objSound = "<object width='1' height='1' id='AUDIOIE" + id_event 
            + " type='application/x-oleobject'  AND_MORE_PARAMS_TO_PLAY_A_MP3"
            + "/>";
    $(objSound).appendTo('#sounds');
    

    如需完整的对象参数,请转到here。

    //To Stop an MP3 and release it instance.
    $('#AUDIOIE' + id_event).empty().remove();
    

    【讨论】:

    【解决方案4】:

    请使用: 让 snd = new Audio(url);

    通过这样做,分配给变量的内存将在堆内存中, 对于您创建的所有实例,而不是在堆栈内存中,这最终会减慢您的系统到您必须等待 GC 清除它的地步。

    根据 javascript 的内存模型,大多数变量声明应该使用 let 或 const。

    var 应该在最罕见的情况下使用。

    【讨论】:

      猜你喜欢
      • 2012-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-30
      • 1970-01-01
      相关资源
      最近更新 更多