Sé que el título no es tan explicativo, pero aquí está la historia: estoy desarrollando un juego de navegador, principalmente usando JavaScript y la biblioteca Mapbox.
Todo funciona bien en el escritorio, Android e iOS, pero aparece un problema en iOS: después de dejar que el juego se ejecute durante unos minutos, el teléfono de repente comienza a tener artefactos gráficos y muestra la mayor parte del texto codificado.
Aquí hay algunas fotos de cómo comienza a verse el teléfono:
Mi pregunta es: ¿qué exactamente en mi código puede causar esto? ¿Una fuga de memoria? ( LE : resultó ser en realidad una pérdida de memoria)
La verdadera pregunta es: ¿Cómo es que casi se puede bloquear todo el teléfono simplemente navegando por una página web? ¿No debería Safari detener esto, o al menos iOS?
Esto no es un problema con este dispositivo específico, ya que este problema se puede reproducir en diferentes dispositivos iPhone. (No estoy tan seguro de las diferentes versiones de iOS).
Cómo puedo reproducir el error:
- Abre el juego (dentro de Safari).
- Déjelo funcionar durante 3-4 minutos.
- Desliza hacia abajo el centro de notificaciones y todo se vuelve loco.
Agregué un video de YouTube que muestra cómo puedo reproducir el error (en mi iPhone 5C).
Parece que el problema aparece primero en el centro de notificaciones (si desliza el menú hacia abajo desde la parte superior).
Por ahora, este problema parece ocurrir solo eniPhone 5C
iOS 9.2.1 (13D15). También ocurre en la nueva versión de iOS 9.3.
Para solucionar este problema, tengo que:
- Cierra la aplicación Safari (en la que está abierta la pestaña del juego).
- Bloquea el teléfono. Después de desbloquearlo, todo vuelve a la normalidad.
Algunos detalles sobre el juego en sí:
- El juego muestra un mapa Mapbox y algunas unidades sobre él (marcadores).
- Un servidor Node.js se ejecuta a 1 tick / segundo y después de cada tick, el estado del juego actualizado se envía al navegador a través de Socket.io.
- Cada vez que el navegador recibe el estado del juego, actualiza los marcadores en consecuencia.
- * El juego también puede actualizar los marcadores si acercas o alejas el zoom o si los seleccionas.
EDIT2:
encontró la pérdida de memoria (como se esperaba). Después de arreglar esta fuga (verifique el undefined
ícono _), el problema ya no ocurre. Esto significa que en algún lugar a lo largo de esas líneas se activa el error de Safari / iOS.
Esto es exactamente cómo se llamaba cada tick, para cada unidad que estaba agrupada (estaba oculta y agrupada con otras dentro de un 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);
Y esta es la icons
matriz:
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
la llamada es de esta biblioteca: https://github.com/kottenator/jquery-circle-progress
MANIFESTACIÓN
Sí, he podido crear un jsFiddle que reproduce el error: https://jsfiddle.net/cte55cz7/14/ Abrir en Safari en iPhone 5C y esperar un par de minutos. En iPhone 6 y iPad mini, la página se bloquea (como se esperaba debido a la pérdida de memoria)
Aquí está el mismo código en un HasteBin, para cualquiera que no quiera ejecutarlo.
SuperUser
. Espero que este sea considerado el lugar adecuado para hacer esta pregunta.Respuestas:
Esta pérdida de memoria probablemente se deba a cómo funciona el motor JS de WebKit [safari webkit-javascript llvm]
y realmente parece ser un desbordamiento de búfer de memoria virtual, que tiene un impacto directo en la RAM restante (compartida y utilizada también por iOS para almacenar elementos gráficos de la interfaz de usuario)
Relativamente al fragmento de código: "[...] encontrar fugas de memoria de jQuery es fácil. Verifique el tamaño de $ .cache. Si es demasiado grande, inspecciónelo y vea qué entradas permanecen y por qué. [...]" ( http://javascript.info/tutorial/memory-leaks )
Permítanme esperar que sea relativo a este bucle 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); }
Suponiendo que se realiza la inspección, y también asumiendo el hecho de que encuentra las entradas, es posible que desee limpiar los datos manualmente con removeData () o puede usar primero $ elem.detach () y luego poner $ (elem) .remove () en setTimeout.
fuente