为什么一个Safari页面打破iOS渲染?

我知道标题并不是说明性的,但这里是一个故事:我正在开发一个浏览器游戏,主要是使用JavaScript和Mapbox库。

在桌面,Android和iOS上一切正常,但iOS上出现了一个问题:让游戏运行几分钟后,手机突然开始出现graphics工件,并显示大部分文本。

以下是手机开始的一些照片: 在这里输入图像说明 在这里输入图像说明 在这里输入图像说明

我的问题是:什么在我的代码可以导致这个? 内存泄漏? ( LE :原来实际上是内存泄漏)
真正的问题是:如何通过浏览网页几乎可以让整个手机变砖? 不应该Safari停止这个,或者至less是iOS?

这对于这个特定的设备来说不是问题,因为这个问题可以在不同的iPhone设备上复制。 (我不太确定不同的iOS版本)。

我如何重现错误:

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

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

  1. closuresSafari应用程序(游戏标签打开)。
  2. locking电话。 解锁后,一切恢复正常。

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

  1. 游戏显示一个Mapbox地图和一些单位(标记)。
  2. 一个Node.js服务器以每秒1滴的速度运行,并在每次滴答之后通过Socket.io将更新的游戏状态发送给浏览器。
  3. 每次浏览器收到游戏状态,都会相应更新标记。
  4. *游戏可能会更新标记,如果你放大或缩小或如果你select它们。

编辑2:发现内存泄漏(如预期)。 修复此漏洞(检查undefined _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); 

这是icons数组:

 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

DEMO

耶,我已经能够创build一个jsFiddle重现错误: https ://jsfiddle.net/cte55cz7/14/在iPhone 5C的Safari上打开,并等待几分钟。 在iPhone 6和iPad mini上,页面崩溃(由于内存泄漏,如预期的那样)

对于任何不想运行它的人来说,这是一个HasteBin中的相同代码。

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

真的看起来像是一个虚拟内存缓冲区溢出,直接影响到剩余的RAM(由iOS共享和用于存储用户界面graphics元素)

相对于这段代码:“[…]查找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); } 

假设检查已完成,并且假设您find条目,则可能需要使用removeData()手动清除数据,或者可以先使用$ elem.detach() ,然后使用$(elem).remove()在setTimeout中。