上下文:一个大型AS3应用程序,可能遭受频繁但不可预测的“停止世界”垃圾收集暂停。当一个人罢工时,可能需要30秒或更长时间才能结束。
这不会在测试中发生,但可能会在生产中发生。
问题:Flash VM是否有可用于检测和记录此类事件的日志记录?我在这里借鉴Java的经验。我已经广泛阅读了Flash GC机器的功能(使用标记/扫描进行参考计数),但我正在寻找一些真实的遥测技术,因为我知道标记/扫描GC事件可以“阻止世界“。
答案 0 :(得分:5)
你是对的。垃圾收集器暂停应用程序执行。
来自reference 的Flash Runtime垃圾收集器算法在标记正在使用的内存时以递增方式运行。它在收集未使用的内存部分时暂停应用程序执行。在增量收集周期结束时发生的暂停可能比期望的更长,并且在某些程序中可以观察到或听到。
据我所知,没有直接的方法可以知道GC是否运行。但是可以在 通过可以存储弱引用键的 通过检查每一帧,您将知道gc stroke是否 您还可以通过检查内存使用情况来监控垃圾回收。文档建议使用 分配给Adobe Flash Player或Adobe AIR且未使用的内存量(以字节为单位)。分配的内存(System.totalMemory)的未使用部分随着垃圾收集的发生而波动。使用此属性来监视垃圾回收。 我会将此值与 结合其他方法,记录实际帧速率或代码块的执行时间可能会有所帮助。这可以通过存储程序"正常运行时间来实现。在变量中并在稍后比较它。 对于Flash运行时处理ActionScript 3.0,此方法返回自ActionScript 3.0(AVM2)的Flash运行时虚拟机启动以来经过的毫秒数。 在每个框架上使用时,您可以将其与 缓解暂停的可能性可能是建议垃圾收集器手动执行。如果实际紧迫性高于参数值, 紧迫性定义为收集者认为它的标记距离,因此触发收集暂停的距离有多近。此函数的紧急参数是一个阈值:仅当实际紧迫度超过阈值时才会调用垃圾收集器。否则,此调用会立即返回而不采取任何操作。 通过调用具有低紧迫值的此函数,应用程序指示它愿意接受必须完成相对大量的标记。另一方面,较高的迫近值表示只有在标记接近完成时才应暂停应用程序。通常情况下,前一种情况下的暂停时间比后者长。 迫近:数字(默认= 0.75) - 介于0和1之间的数字,其中0表示不太迫近,1表示最迫切。小于0的值默认为0.25。大于1.0的值默认为1.0。 NaN默认为0.75 检查垃圾收集器是否运行
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;
}
}
}
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
private function onEnterFrame(event:Event):void
{
var gcRan:Boolean = GCTest.didGCRun();
}
内存使用
System.freeMemory()
System.totalMemoryNumber()
验证执行时间
var startTime:int = getTimer();
// execution or frame change
var executionTime:int = getTimer() - startTime;
stage.frameRate
进行比较并检查是否存在差异。建议垃圾收集器执行
System.pauseForGCIfCollectionImminent(imminence:Number = 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播放器版本,模式......)如果频繁,您应该能够重现它。