如何解决JavaScript 内存泄漏WebWorker、Canvas、IndexedDB
我需要一些帮助来查找小型浏览器/WebWorker JavaScript 中的内存泄漏。我将其追踪到这段代码中:
/**
* Resizes an Image
*
* @function scaleImage
* @param {object} oImageBlob blob of image
* @param {int} iHeight New height of Image
* @return {ImageBitmap} ImageBitmap Object
*/
async function scaleImage(oImageBlob,iHeight) {
var img = await self.createImageBitmap(oImageBlob);
var iWidth = Math.round( ( img.width / img.height ) * iHeight);
var canvas = new OffscreenCanvas(iWidth,iHeight);
var ctx = canvas.getContext('2d');
ctx.drawImage(img,canvas.width,canvas.height);
return(canvas.transferToImageBitmap());
}
它来自:
[inside a web worker: Some looping that calls this about 1200 times while parsind files from a s3 bucket ...]
var oImageBlob = await new Response(oS3Object.Body,{}).blob();
var oThumbnail = await scaleImage(oImageBlob,100);
await IDBputData(oInput.sFileKey,oImageBlob,oInput.sstore,oThumbnail)
[... end of the loop]
/**
* Put @R_341_4045@ion to IndexedDB
*
* @function IDBputData
* @param {string} sKey key of @R_341_4045@ion
* @param {string} sValue @R_341_4045@ion to upload
* @param {string} sstore name of object store
* @param {object} oThumbnail optrional,default: null,thumbnail image
* @return {object} - SUCCESS: array,IndexedDB Identifyer "key"
* - FAIL: Error Message
*/
async function IDBputData(sKey,sValue,sstore,oThumbnail=null) {
var oGeneratedKeys = {};
if(sstore=="panelStore"){
oGeneratedKeys = await getKeyfromSKey(sKey);
}
return new Promise((resolve,reject) => {
const tx = oConn.transaction(sstore,'readwrite');
const store = tx.objectStore(sstore);
var request = {}
request = store.put({panelkey: oGeneratedKeys.panelkey,layerkey: oGeneratedKeys.layerkey,countrycode: oGeneratedKeys.countrycode,value: sValue,LastModified: new Date(),oThumbnail: oThumbnail});
request.onsuccess = () => (oThumbnail.close(),resolve(request.result));
request.onerror = () => (oThumbnail.close(),reject(request.error));
});
}
当我在 Chrome 中以这种方式运行它时,它将消耗我可用的每一位 RAM(大约 8 GB),然后崩溃。 (具有 cpu/GPU 共享 RAM 的笔记本电脑)。
当我改变时
var oThumbnail = await scaleImage(oImageBlob,100);
到
var oThumbnail = null;
Chrome 的 RAM 消耗保持在 800 MB 左右,因此必须具有最顶层的函数“scaleImage”。
我尝试调整它,但没有成功。
/**
* Resizes an Image
*
* @function scaleImage
* @param {object} oImageBlob blob of image
* @param {int} iHeight New height of Image
* @return {ImageBitmap} ImageBitmap Object
*/
async function scaleImage(oImageBlob,iHeight) {
var img = await self.createImageBitmap(oImageBlob);
var iWidth = Math.round( ( img.width / img.height ) * iHeight);
var canvas = new OffscreenCanvas(iWidth,iHeight);
var ctx = canvas.getContext('2d');
ctx.drawImage(img,canvas.height);
var oImageBitmap = canvas.transferToImageBitmap();
ctx = null;
canvas = null;
iWidth = null;
img = null;
return(oImageBitmap);
}
非常感谢任何帮助。
解决方法
要使 ImageBitmap 以最有效的方式发布其位图数据,您必须在完成后调用其 .close()
方法。
但实际上,您不需要这个 scaleImage
函数。 createImageBitmap()
有一个 resizeHeight
选项,如果您在没有 resizeWidth
的情况下使用它,您将通过保持纵横比精确来调整图像大小,就像您在函数中所做的那样,除了它不需要两次分配位图。
一旦您有了这个调整大小的 ImageBitmap,您就可以将它传输到 BitmapRenderingContext(它将在内部 close()
原始 ImageBitmap)并从该渲染器调用 transferToBlob()
。
这对您的计算机来说应该更轻。
async function worker_script() {
const blob = await fetch( "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png" ).then( (resp) => resp.blob() );
// resize from createImageBitmap directly
const img = await createImageBitmap( blob,{ resizeHeight: 100 } );
const canvas = new OffscreenCanvas( img.width,img.height );
canvas.getContext( "bitmaprenderer" )
.transferFromImageBitmap( img ); // this internally closes the ImageBitmap
const resized_blob = await canvas.convertToBlob();
// putInIDB( resized_blob );
// for the demo we pass that Blob to main,but one shouldn't have to do that
// show the canvas instead ;)
postMessage( { blob: resized_blob,width: img.width } );
// to be safe,we can even resize our canvas to 0x0 to free its bitmap entirely
canvas.width = canvas.height = 0;
}
// back to main
const worker = new Worker( getWorkerURL() );
worker.onmessage = ({ data: { blob,width } }) => {
const img = new Image();
img.src = URL.createObjectURL( blob );
img.onload = (evt) => URL.revokeObjectURL( img.src );
document.body.append( img );
console.log( "ImageBitmap got detached?",width === 0 );
};
function getWorkerURL() {
const content = "!" + worker_script.toString() + "();";
const blob = new Blob( [ content ],{ type: "text/javascript" } );
return URL.createObjectURL( blob );
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。