提问者:小点点

为什么Safari页面会破坏iOS渲染?


我知道标题不是那么解释,但故事是这样的:我正在开发一个浏览器游戏,主要使用JavaScript和Mapbox库。

在台式机,Android和iOS上一切正常,但在iOS上出现了一个问题:让游戏运行几分钟后,手机突然开始出现图形伪像并显示大部分打乱的文本。

我的问题是:我的代码中到底是什么导致了这种情况?内存泄漏?(乐:原来是内存泄漏)< br >真正的问题是:你怎么能通过简单地浏览网页就几乎能把整个手机都砌成砖呢?难道Safari不应该停止这种行为,或者至少停止iOS吗?

这不是这个特定设备的问题,因为这个问题可以在不同的iPhone设备上重现。(我不太确定不同的iOS版本)。

我如何重现错误:

  1. 打开游戏(在 Safari 中)。
  2. 让它运行 3-4 分钟。
  3. 向下滑动通知中心,一切都变得疯狂。
    我添加了一个YouTube视频,展示了如何重现错误(在我的iPhone 5C上)。
    问题似乎首先出现在通知中心(如果您从顶部向下滑动菜单)。
    至于目前,这个问题似乎只发生在iPhone 5C iOS 9.2.1(13D15)上。它也发生在新的iOS 9.3版本上。

为了解决这个问题,我必须:

  1. 关闭Safari应用程序(其中游戏选项卡打开)。
  2. 锁定手机。解锁后一切恢复正常。

关于游戏本身的一些细节:

    < li >游戏显示了一个地图框地图和其上的一些单位(标记)。 < Li > node . js服务器以1 tick/秒的速度运行,在每个tick之后,更新的游戏状态通过Socket.io发送到浏览器。 < li >每次浏览器收到游戏状态时,都会相应地更新标记。 < li > *如果您放大或缩小或选择标记,游戏可能也会更新标记。

编辑2:发现内存泄漏(如预期的那样)。修复此泄漏(检查未定义的_icon)后,问题不再发生。这意味着,沿着这些行的某个地方触发了Safari / iOS错误。

以下是每个被聚类的单位(在 MarkerCluster 中隐藏并与其他单位分组)的确切名称:

    var $icon = $(marker._icon); // marker._icon is undefined because of the clustering

    $icon.html('');

    $icon.append($('<img class="markerIcon" src="' + options.iconUrl + '" />'));

    var iconX = 10;
    var iconY = -10;
    var iconOffset = 0;

    for(var v in this.icons) {
        this.icons[v].css('z-index', + $icon.css('z-index') + 1);
        this.icons[v].css('transform', 'translate3d(' + iconX + 'px,' 
                                + (iconY + iconOffset) + 'px,' + '0px)');
        iconOffset += 20;

        this.icons[v].appendTo($icon);
    }

    // Fire rate icons
    this.attackRateCircle = $('<div class="circle"></div>');
    this.attackRateCircle.circleProgress({
        value: 0,
        size: 16,
        fill: { color: "#b5deff" },
        emptyFill: 'rgba(0, 0, 0, 0.5)',
        startAngle:  -Math.PI / 2,
        thickness: 4,
        animation: false,
    });
    this.attackRateCircle.hide();

    // Create and display the healthbar
    this.healthBar = $('<div>').addClass('healthBar ');
    this.healthBar.css('z-index', $icon.css('z-index'));
    this.healthBarFill = $('<span class="fill">');
    this.healthBar.append(this.healthBarFill);

    $icon.append(this.healthBar);
    $icon.append(this.attackRateCircle);

这是图标数组:

this.icons = {
    attack_order: $('<img src="img/attack.png" class="status_icon">'),
    attack: $('<img src="img/damage.png" class="status_icon icon_damage">'),
    hit: $('<img src="img/hit.png" class="status_icon icon_hit">'),
};

circleProgress调用来自此库:https://github.com/kottenator/jquery-circle-progress

耶,我已经能够创建一个jsFiddle来重现这个bug:在iPhone 5C上的Safari上打开https://jsfiddle.net/cte55cz7/14/,然后等几分钟。在iPhone 6和iPad mini上,页面崩溃(由于内存泄漏,这是意料之中的)

这里是HasteBin中的相同代码,供不想运行它的人使用。


共1个答案

匿名用户

这种内存泄漏可能是由于“WebKit的JS引擎”的工作方式[safari webkit-javascript llvm]

并且看起来像是一个虚拟内存缓冲区溢出,直接影响剩余的RAM(iOS也共享和使用它来存储用户界面图形元素)

相对于这段代码:“[…]查找jQuery内存泄漏很容易。请检查$.cache的大小。如果太大,请检查它,看看哪些条目保留下来以及原因。[…]”(http://javascript.info/tutorial/memory-leaks)

让我期望它是相对于这个 for 循环的:

for(var v in this.icons) {
    this.icons[v].css('z-index', + $icon.css('z-index') + 1);
    this.icons[v].css('transform', 'translate3d(' + iconX + 'px,' 
                            + (iconY + iconOffset) + 'px,' + '0px)');
    iconOffset += 20;

    this.icons[v].appendTo($icon);
}

假设检查已经完成,并且还假设您找到了条目,您可能希望使用refveData()手动清理数据,或者您可以先使用$elem.detach(),然后在setTimeout中输入$(elem)。