Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/441.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript中的内存泄漏(WebWorker、Canvas、IndexedDB)_Javascript_Memory Leaks_Html5 Canvas_Indexeddb_Offscreen Canvas - Fatal编程技术网

JavaScript中的内存泄漏(WebWorker、Canvas、IndexedDB)

JavaScript中的内存泄漏(WebWorker、Canvas、IndexedDB),javascript,memory-leaks,html5-canvas,indexeddb,offscreen-canvas,Javascript,Memory Leaks,Html5 Canvas,Indexeddb,Offscreen Canvas,我需要一些帮助来查找浏览器/WebWorker JavaScript中的内存泄漏。我在这段代码中找到了它: /** * Resizes an Image * * @function scaleImage * @param {object} oImageBlob blob of image * @param {int} iHeight New height of Image * @return {ImageBi

我需要一些帮助来查找浏览器/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, 0, 0, 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 information to IndexedDB 
     *
     * @function IDBputData 
     * @param {string}  sKey        key of information
     * @param {string}  sValue      information 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中以这种方式运行它时,它将消耗我所有空闲内存(大约8GB),然后崩溃。(带CPU/GPU共享RAM的笔记本电脑)

当我改变

         var oThumbnail = await scaleImage(oImageBlob, 100);

Chrome的RAM消耗保持在800MB左右,因此必须有最顶级的函数“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, 0, 0, canvas.width, canvas.height);      

    var oImageBitmap = canvas.transferToImageBitmap();

    ctx = null;
    canvas = null;
    iWidth = null;
    img = null;

    return(oImageBitmap);
}

非常感谢您的帮助。

要使ImageBitmap以最有效的方式发布其位图数据,您必须在完成后调用其方法

但实际上,您不需要这个
scaleImage
函数。有一个
resizeHeight
选项,如果您在使用该选项时没有使用
resizeWidth
选项,则可以通过保持纵横比来精确调整图像大小,就像您在函数中所做的那样,只是不需要指定位图两次

一旦调整了此图像位图的大小,就可以将其传输到(将在内部
close()
原始图像位图),并从该渲染器调用
transferToBlob()
)。 这对你的电脑来说应该更轻一些

async function worker\u script(){
const blob=等待获取(“https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png)然后((resp)=>resp.blob());
//直接从createImageBitmap调整大小
const img=wait createImageBitmap(blob,{resizeHeight:100});
const canvas=新的偏置画布(img.width,img.height);
getContext(“位图渲染器”)
.transferFromImageBitmap(img);//这会在内部关闭ImageBitmap
const resized_blob=await canvas.convertToBlob();
//putinib(调整大小的\u blob);
//对于演示,我们将该Blob传递给main,但不必这样做
//改为显示画布;)
postMessage({blob:resized_blob,width:img.width});
//为了安全起见,我们甚至可以将画布调整为0x0以完全释放其位图
canvas.width=canvas.height=0;
}
//回到主站
const-worker=新工作者(getWorkerURL());
worker.onmessage=({data:{blob,width}})=>{
const img=新图像();
img.src=URL.createObjectURL(blob);
img.onload=(evt)=>URL.revokeObjectURL(img.src);
文件.正文.附加(img);
log(“ImageBitmap是否已分离?”,宽度==0);
};
函数getWorkerURL(){
const content=“!”+worker_script.toString()+“();”;
constblob=newblob([content],{type:“text/javascript”});
返回URL.createObjectURL(blob);

}
当使用
store.put创建的请求解决时,您应该清理图像位图。示例
request.onsuccess=()=>(oThumbnail.close(),resolve(request.result))
(在
onerror
中执行相同操作)调用
ImageBitmap.close()
将处理位图使用的资源。@Blindman67听起来不错,但在几分钟前对其进行测试后,我可以说:没有任何区别。:-(我相应地更新了问题中的代码。但我肯定还遗漏了一些东西。:-(你有没有清理过你不断创建的屏幕外画布
var canvas=new OffscreenCanvas(iWidth,iHeight)
?@根据我的研究canvas=null;应该可以。我在问题的最后一个代码段中尝试了这个方法。你认为我做错了什么吗?@模糊画布的作用域是函数,因此在函数返回时被取消引用。谢谢。我同意你的解决方案,但是,我有两点意见:->创建eImageBitmap()和resizeHeight都可以工作。但是,即使质量“高”,它也会导致明显的低质量。另外,我对几百个全高清文件的测试表明,在Chrome上80%的情况下,它的速度与Chrome一样快,甚至更慢。(不,我也没想到。:-)->Blindman67和Underfuse首先帮助我找到了正确的解决方案(参见问题的评论),因此,如果他们中的一个想发布一个公平的答案,我会再等一天。你的测试结果真的很奇怪……通过这条路,我肯定做得更少(我上个月在Chrome的实现中修复了一个不相关的bug)。如果我有时间,我会自己设置一个测试,看看发生了什么,但是首先,你能再次检查一下你的系统上是否启用了所有硬件加速吗(chrome://gpu/)。阅读这里的评论,只有Blindman67给了你正确的建议。如果有帮助,我可以尝试分享有关我的测试设置的详细信息。“图形功能状态”下的所有内容都已启用或硬件加速,尽管“Vulkan”我的印象是,不将可选参数传递给createImageBitmap可能会跳过比canvas构造函数慢一些的代码。我不知道chorme的实现端,尽管这只是一个猜测。运行一个非常快速的测试(),在我的计算机上,bitmaprender的性能比2D环境好很多:对于100张原始Blob的完整副本的图像,15秒比21秒(我最终得到的是13秒比19秒)。关于质量,在createImageBitmap中使用resizeQuality“high”进行缩小时,确实出现了一些问题……在“low”和“Middle”之间有更大的区别在“低”和“高”之间…drawImage似乎与“高”和“中”oO绘制了相同的图形
/**
 * 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, 0, 0, canvas.width, canvas.height);      

    var oImageBitmap = canvas.transferToImageBitmap();

    ctx = null;
    canvas = null;
    iWidth = null;
    img = null;

    return(oImageBitmap);
}