Actionscript 3 AS3-垃圾收集器何时运行?

Actionscript 3 AS3-垃圾收集器何时运行?,actionscript-3,flash,garbage-collection,Actionscript 3,Flash,Garbage Collection,道歉,如果这是一个骗局;我找不到它 我已经阅读并理解了grant skinner关于AS3垃圾收集器的博客- , 但我的问题不在这里 这是我的问题 假设我编写了一些AS3代码,如: statementOne; statementTwo; 垃圾收集器是否有可能在我的两条语句之间运行,或者只有在我的“用户”代码完成并将控制权返回给flash之后才运行 我们有一个有时很慢的A星代码块, 我想消除GC作为潜在的罪魁祸首。 代码块显然比我上面的例子更复杂, 但它不涉及任何事件或其他异步内容 蒂亚, Or

道歉,如果这是一个骗局;我找不到它

我已经阅读并理解了grant skinner关于AS3垃圾收集器的博客- , 但我的问题不在这里

这是我的问题

假设我编写了一些AS3代码,如:

statementOne;
statementTwo;
垃圾收集器是否有可能在我的两条语句之间运行,或者只有在我的“用户”代码完成并将控制权返回给flash之后才运行

我们有一个有时很慢的A星代码块, 我想消除GC作为潜在的罪魁祸首。 代码块显然比我上面的例子更复杂, 但它不涉及任何事件或其他异步内容

蒂亚,
Orion

您无法确定GC何时运行。如果您试图阻止某个内容被GC'd,请在某处保留对它的引用。

据我所知,这没有文档记录。我有一种感觉,当你的代码被执行时,GC不会运行(也就是说,当你的代码在执行堆栈上时;每一帧,播放器都会创建一个新的堆栈来使用代码)。显然,这来自于观察和我自己对Flash的体验,所以我不会说这是100%准确的。希望这是一个有根据的猜测

下面是一个简单的测试,似乎可以证明上述情况是正确的:

package {
    import flash.display.Sprite;
    import flash.net.FileReference;
    import flash.system.System;
    import flash.utils.Dictionary;
    import flash.utils.setTimeout;

    public class test extends Sprite
    {

        private var _dict:Dictionary = new Dictionary(true);

        public function test()
        {
            testGC();
            setTimeout(function():void { 
                traceCount();
            },2000);            
        }

        private function testGC():void {
            var fileRef:FileReference;
            for(var i:int = 0; i < 100; i++) {
                fileRef = new FileReference();
                _dict[fileRef] = true;
                traceCount();
                System.gc();
            }
        }

        private function traceCount():void {
            var count:int = 0;
            for(var i:* in _dict) {
                count++;
            }
            trace(count);
        }

    }
}
包{
导入flash.display.Sprite;
导入flash.net.FileReference;
导入flash.system.system;
导入flash.utils.Dictionary;
导入flash.utils.setTimeout;
公共类测试扩展了Sprite
{
私有变量dict:Dictionary=新字典(true);
公共功能测试()
{
testGC();
setTimeout(函数():void{
traceCount();
},2000);            
}
私有函数testGC():void{
var fileRef:FileReference;
对于(变量i:int=0;i<100;i++){
fileRef=新的FileReference();
_dict[fileRef]=真;
traceCount();
gc();
}
}
私有函数traceCount():void{
变量计数:int=0;
对于(变量i:*在目录中){
计数++;
}
跟踪(计数);
}
}
}
当涉及到
FileReference
对象时,GC似乎特别贪婪(同样,这是根据我的经验得出的;据我所知,这没有文档记录)

现在,如果运行上述代码,即使显式调用
System.gc()
,当函数在堆栈上时,对象也不会被收集:查看字典的计数(由于明显的原因,设置为使用弱引用),您可以看到它们仍然是活动的

再次跟踪此计数时,在不同的执行堆栈中(由对setTimeout的异步调用引起),所有对象都已释放


所以,我认为GC似乎不是您案例中表现不佳的罪魁祸首。同样,这只是一个观察,GC在这个测试中执行用户代码时没有运行并不意味着它永远不会运行。很可能不会,但由于没有记录在案,恐怕无法确定。我希望这有帮助

GC不会像示例中那样在同一堆栈/同一帧上的两条语句之间运行。内存将在执行下一帧之前释放。这就是大多数现代虚拟机环境的工作方式。

垃圾收集器不是线程化的,所以一般来说,在代码运行时它不会运行。然而,有一个例外情况并非如此

new
关键字将在内存不足时调用垃圾收集器

您可以运行此代码来观察此行为:

var vec:Vector.<*> = new Vector.<*>(9001);
for (;;) {
    vec[0] = new Vector.<*>(9001);
    vec = vec[0];
}
var-vec:Vector.=新载体(9001);
对于(;;){
向量[0]=新向量(9001);
vec=vec[0];
}

内存使用率将迅速上升到最大值(对我来说是1GB),然后一直保持到时间截止。

这里有很多好的答案,但我认为有一些微妙之处尚未解决

  • Flash player实现两种垃圾收集。一种是引用计数,其中Flash保存对每个对象的传入引用的计数,并且知道当计数达到零时,对象可以被释放。第二种方法是标记扫描,Flash偶尔会搜索和删除孤立的对象组(对象相互引用,但整个组没有传入引用)
  • 根据规范,任何一种垃圾收集都可能随时发生。玩家无法保证对象何时被释放,标记扫描甚至可能会分散在多个帧上。此外,还不能保证在Flash player版本、平台甚至浏览器之间,地面军事系统的时间会保持不变。因此,在某种程度上,了解GCs是如何触发的并不是很有用,因为你无法知道你的知识的适用范围有多广
  • 撇开前面的一点不谈,一般来说,标记扫描很少发生,而且只在某些情况下触发。我知道某些播放器/操作系统配置每N秒会触发一次标记/扫描,或者当播放器超过总可用内存的P%时触发一次标记/扫描,但这是很久以前的事了,细节会有所改变。相比之下,引用计数GCs可能经常发生——至少在帧之间。我认为我没有看到它们更频繁地发生,但这并不意味着它不可能发生(至少在某些情况下)
  • 最后,谈谈您的具体问题:根据我的经验,GC不太可能与您的性能问题有任何关系。引用计数的GC处理很可能在循环期间发生,但通常这是一件好事——这种收集速度非常快,并使内存使用保持可控。管理裁判的全部要点