检测/记录AS3“停止世界”GC暂停

时间:2014-08-26 18:52:32

标签: actionscript-3 flash garbage-collection

上下文:一个大型AS3应用程序,可能遭受频繁但不可预测的“停止世界”垃圾收集暂停。当一个人罢工时,可能需要30秒或更长时间才能结束。

这不会在测试中发生,但可能会在生产中发生。

问题:Flash VM是否有可用于检测和记录此类事件的日志记录?我在这里借鉴Java的经验。我已经广泛阅读了Flash GC机器的功能(使用标记/扫描进行参考计数),但我正在寻找一些真实的遥测技术,因为我知道标记/扫描GC事件可以“阻止世界“。

4 个答案:

答案 0 :(得分:5)

你是对的。垃圾收集器暂停应用程序执行。

  

Flash Runtime垃圾收集器算法在标记正在使用的内存时以递增方式运行。它在收集未使用的内存部分时暂停应用程序执行。在增量收集周期结束时发生的暂停可能比期望的更长,并且在某些程序中可以观察到或听到。

来自reference

检查垃圾收集器是否运行

据我所知,没有直接的方法可以知道GC是否运行。但是可以在ENTER_FRAME上执行测试功能,并检查自上次函数调用后是否已收集垃圾。自上一帧以来有效。

通过可以存储弱引用键的Dictionary,可以查看是否已收集对象。如果是这种情况,垃圾收集必须运行。在下面的类中,我创建了一个新对象,以便稍后检查它是否已被收集。

package
{
    import flash.display.Sprite;
    import flash.utils.Dictionary;

    public class GCTest
    {
        private static var dict:Dictionary = null;

        public static function didGCRun():Boolean
        {
            if ( dict == null ) {
                dict = new Dictionary(true);
            }

            var hasKeys:Boolean = false;

            for ( var obj:* in dict ) {
                hasKeys = true;
                break;
            }

            if ( hasKeys ) {
                return false;
            }
            else {
                dict[new Sprite()] = null;
                return true;
            }
        }       
    }
}    

通过检查每一帧,您将知道gc stroke是否

addEventListener(Event.ENTER_FRAME, onEnterFrame);

private function onEnterFrame(event:Event):void
{
    var gcRan:Boolean = GCTest.didGCRun();
}

内存使用

您还可以通过检查内存使用情况来监控垃圾回收。文档建议使用System.freeMemory()

  

分配给Adobe Flash Player或Adobe AIR且未使用的内存量(以字节为单位)。分配的内存(System.totalMemory)的未使用部分随着垃圾收集的发生而波动。使用此属性来监视垃圾回收。

我会将此值与System.totalMemoryNumber()

结合使用

验证执行时间

结合其他方法,记录实际帧速率或代码块的执行时间可能会有所帮助。这可以通过存储程序"正常运行时间来实现。在变量中并在稍后比较它。

使用getTimer()

  

对于Flash运行时处理ActionScript 3.0,此方法返回自ActionScript 3.0(AVM2)的Flash运行时虚拟机启动以来经过的毫秒数。

var startTime:int = getTimer();
// execution or frame change
var executionTime:int = getTimer() - startTime;

在每个框架上使用时,您可以将其与stage.frameRate进行比较并检查是否存在差异。

建议垃圾收集器执行

缓解暂停的可能性可能是建议垃圾收集器手动执行。如果实际紧迫性高于参数值,System.pauseForGCIfCollectionImminent(imminence:Number = 0.75)将暂停程序执行。

  

紧迫性定义为收集者认为它的标记距离,因此触发收集暂停的距离有多近。此函数的紧急参数是一个阈值:仅当实际紧迫度超过阈值时才会调用垃圾收集器。否则,此调用会立即返回而不采取任何操作。

     

通过调用具有低紧迫值的此函数,应用程序指示它愿意接受必须完成相对大量的标记。另一方面,较高的迫近值表示只有在标记接近完成时才应暂停应用程序。通常情况下,前一种情况下的暂停时间比后者长。

     

迫近:数字(默认= 0.75) - 介于0和1之间的数字,其中0表示不太迫近,1表示最迫切。小于0的值默认为0.25。大于1.0的值默认为1.0。 NaN默认为0.75

来自reference

答案 1 :(得分:0)

Adobe Scout是一个很好的工具来分析AS3项目。

答案 2 :(得分:0)

您可以使用:

setInterval( function()
{
    trace(System.totalMemory);
},1000);

每当垃圾收集器工作且忙碌时,内存量会发生很大变化。如果你看到内存发生了变化,同时程序暂停或出现故障,那么它就是由GC造成的。

答案 3 :(得分:0)

首先,您的生产环境是什么? flash播放器,AIR桌面,AIR移动? 你的应用程序应该执行计算繁重的任务吗?

30多秒的垃圾收集似乎很大,但如果停顿确实是由垃圾收集器引起的,那么记录它对你没什么帮助,除了确认你的假设。

我要做的第一件事就是用遥测技术广泛测试你的应用程序 如果您看到GC的任何异常活动迹象(大红色尖峰,或每帧超过几个百分点的永久性gc噪声),请激活内存分配遥测并查找/消除内存实例中的瓶颈。请记住,即使释放的分配也会对gc产生影响,因此使用池,并且对每个帧上发生的分配都要非常严格,即使少量分配也会产生重大影响。 请注意,解析大型xml或json文件的分配非常繁重。

确定您的应用程序正确使用内存后,请检查(或让测试人员/测试版测试人员/用户检查)问题是否仍然存在,或者问题是否频繁发生,甚至是否已消失。< / p>

如果它不起作用,您至少会首先改善应用的性能和内存占用 你没有关于暂停性质的更多信息,你是否考虑过除GC以外的其他选择?也许问题不是你搜索它的地方: 您可以尝试使用UncaughtErrorEvent捕获并记录所有错误(然后使用URLLoader将错误堆栈发布到错误记录服务)。它可以帮助您检测难以在生产中重现错误,例如:

  • 卡在一个函数中:应该在15秒后抛出一个ScriptTimeoutError(代码#1502),这将在flash player调试器中打开一个弹出窗口。

  • 任何其他错误都会中断整个堆栈,这可能会使您的应用程序处于无响应状态。也许一些长时间超时会让它再次响应?

BTW如果您没有记录并且从未复制过应用程序,您如何知道应用程序正在经历30秒以上的冻结?如果它是最终用户报告的错误,请尝试获取更多信息(获取他们的操作系统,Flash播放器版本,模式......)如果频繁,您应该能够重现它。