javascript - liberar - Fuga de URI de datos en Safari(era: Pérdida de memoria con lienzo HTML5)
liberar memoria js (4)
Eso es muy interesante. Vale la pena informar como un error a los distintos proveedores de navegadores (mi opinión es que no debería ocurrir). Es posible que responda de la siguiente manera: "No haga eso, en lugar de eso o lo otro", pero al menos sabrá la respuesta correcta y tendrá algo interesante para escribir en una publicación de blog (definitivamente habrá más gente que la encontrará). este problema).
Una cosa que hay que intentar es desactivar la imagen src (y el controlador de carga) justo después de la llamada a drawImage. Puede que no libere toda la memoria, pero puede recuperar la mayor parte.
Si eso no funciona, siempre puede crear un grupo de objetos de imagen y reutilizarlos una vez que hayan dibujado el lienzo. Eso es una molestia porque tendrá que hacer un seguimiento del estado de esos objetos y también establecer su grupo en un tamaño adecuado (o hacer que crezca / disminuya según el tráfico).
Por favor informe sus resultados. Estoy muy interesado porque uso una técnica similar para una de las codificaciones noVNC de noVNC en noVNC (y estoy seguro de que a otros también les interesará).
He creado una página web que recibe mapas de bits codificados en base64 a través de un Websocket y luego los dibuja en un lienzo. Funciona perfectamente. Excepto, el uso de memoria del navegador (ya sea Firefox, Chrome o Safari) aumenta con cada imagen y nunca se desactiva. Por lo tanto, debe haber una pérdida de memoria en mi código o algún otro error. Si comento la llamada a context.drawImage, la pérdida de memoria no se produce (pero, por supuesto, la imagen nunca se dibuja). A continuación se muestran fragmentos de mi página web. Cualquier ayuda es apreciada. ¡Gracias!
// global variables
var canvas;
var context;
...
ws.onmessage = function(evt)
{
var received_msg = evt.data;
var display_image = new Image();
display_image.onload = function ()
{
context.drawImage(this, 0, 0);
}
display_image.src = ''data:image/bmp;base64,''+received_msg;
}
...
canvas=document.getElementById(''ImageCanvas'');
context=canvas.getContext(''2d'');
...
<canvas id="ImageCanvas" width="430" height="330"></canvas>
ACTUALIZACIÓN 19/12/2011
Puedo solucionar este problema creando / destruyendo dinámicamente el lienzo cada 100 imágenes o más con createElement / appendChild y removeChild. Después de eso, no tengo más problemas de memoria con Firefox y Chrome.
Sin embargo, Safari todavía tiene un problema de uso de memoria, pero creo que es un problema diferente, no relacionado con Canvas. Parece que hay un problema con cambiar repetidamente el "src" de la imagen en Safari, como si nunca liberara esta memoria.
display_image.src = ''data:image/bmp;base64,''+received_msg;
Este es el mismo problema que se describe en el siguiente sitio: http://waldheinz.de/2010/06/webkit-leaks-data-uris/
ACTUALIZACIÓN 21/12/2011
Esperaba solucionar este problema de Safari al convertir mi cadena base64 recibida en un blob (con una función "dataURItoBlob" que encontré en este sitio) y volver a una URL con window.URL.createObjectURL, configurando mi imagen src para esto URL y luego libere la memoria llamando a window.URL.revokeObjectURL. Conseguí que todo funcionara, y Chrome y Firefox muestran las imágenes correctamente. Desafortunadamente, Safari no parece tener soporte para BlobBuilder, por lo que no es una solución que pueda usar. Esto es extraño, ya que muchos lugares, incluido el libro O''Reilly "Programming HTML5 Applications", indican que BlobBuilder es compatible con Safari / WebKit Nightly Builds. Descargué la última compilación nocturna de Windows de http://nightly.webkit.org/ y ejecuté WebKit.exe, pero BlobBuilder y WebKitBlobBuilder aún no están definidos.
ACTUALIZACIÓN 01/03/2012
Ok, finalmente lo arreglé descodificando la cadena URI de datos codificados en base64 con atob () y luego creando una matriz de datos de píxeles y escribiéndola en el lienzo con putImageData (consulte http://beej.us/blog/2010/02/html5s-canvas-part-ii-pixel-manipulation/ ). Al hacerlo de esta manera (en lugar de modificar constantemente el "src" de una imagen y llamar a drawImage en la función de carga), ya no veo una pérdida de memoria en Safari ni en ningún navegador.
No creo que esto sea un error. El problema parece ser que las imágenes se apilan unas sobre otras. Por lo tanto, para borrar la memoria, debe usar clearRect () para borrar su lienzo antes de dibujar la nueva imagen en él.
ctx.clearRect (0, 0, canvas.width, canvas.height);
Probablemente estés dibujando la imagen muchas veces más de lo que esperas. intente agregar un contador y envíe el número a una alerta oa un div en la página para ver cuántas veces se está dibujando la imagen.
Sin un código de trabajo real solo podemos especular sobre por qué.
Si estás enviando la misma imagen una y otra vez, estás creando una nueva imagen cada vez. Esto es malo. Usted querría hacer algo como esto:
var images = {}; // a map of all the images
ws.onmessage = function(evt)
{
var received_msg = evt.data;
var display_image;
var src = ''data:image/bmp;base64,''+received_msg;
// We''ve got two distinct scenarios here for images coming over the line:
if (images[src] !== undefined) {
// Image has come over before and therefore already been created,
// so don''t make a new one!
display_image = images[src];
display_image.onload = function () {
context.drawImage(this, 0, 0);
}
} else {
// Never before seen image, make a new Image()
display_image = new Image();
display_image.onload = function () {
context.drawImage(this, 0, 0);
}
display_image.src = src;
images[src] = display_image; // save it for reuse
}
}
Hay formas más eficientes de escribir eso (estoy duplicando el código de carga, por ejemplo, y no estoy comprobando si una imagen ya está completa). Sin embargo, dejaré esas partes en tus manos, entiendes la idea.