Web工作程序在HTML5画布处理中内存不足

时间:2014-04-11 04:03:54

标签: javascript html5 multithreading canvas web-worker

在主线程中:我通过getImageData方法获取源图像数组。它是一个uint8ClampedArray来记录我的图像数据。

这是我在web worker中的代码: (这段代码会给我一个高分辨率的图像,但操作的结果太大了)

 self.addEventListener('message', function(e){
    var scale = e.data['scale'], cvWidth = e.data['width'], cvHeight = e.data['height'], sBufferData = e.data['sBuffer'].data;

    var sq = scale*scale,   //pixel of source within target
        sw = cvWidth, sh = cvHeight,
        sx = 0, sy = 0, sIdx = 0,
        tw = Math.floor(sw * scale), th = Math.floor(sh * scale),
        tx = 0, ty = 0, tIdx = 0,
        TX = 0, TY = 0, yIdx = 0,
        w = 0, nw = 0, wx = 0, nwx = 0, wy = 0, nwy = 0,
        sR = 0, sG = 0, sB = 0,
        crossX = false, crossY = false,
        tBuffer = new Float32Array(3 * sw * sh);

    for( sy=0; sy<sh; sy++ ) {
        ty = sy * scale; TY = 0 | ty; yIdx = 3 * TY * tw; crossY = (TY != (0 | ty + scale));
        if(crossY) { wy = (TY + 1 - ty); nwy = (ty + scale - TY - 1); }
        for( sx=0; sx<sw; sx++, sIdx+=4 ) {
            tx = sx * scale; TX = 0 | tx; tIdx = yIdx + TX * 3; crossX = (TX != (0 | tx + scale));
            if(crossX) { wx = (TX + 1 - tx); nwx = (tx + scale - TX - 1); }
            sR = sBufferData[sIdx+0]; sG = sBufferData[sIdx+1]; sB = sBufferData[sIdx+2];
            if(!crossX && !crossY) {
                tBuffer[tIdx+0] += sR * sq; tBuffer[tIdx+1] += sG * sq; tBuffer[tIdx+2] += sB * sq;
            } else if(crossX && !crossY) {
                w = wx * scale;
                tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
                nw = nwx * scale
                tBuffer[tIdx+3] += sR * nw; tBuffer[tIdx+4] += sG * nw; tBuffer[tIdx+5] += sB * nw;
            } else if(crossY && !crossX) {
                w = wy * scale;
                tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
                nw = nwy * scale
                tBuffer[tIdx+3 * tw+0] += sR * nw; tBuffer[tIdx+3 * tw+1] += sG * nw; tBuffer[tIdx+3 * tw+2] += sB * nw;
            } else {
                w = wx * wy;
                tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
                nw = nwx * wy;  //for TX + 1; TY px
                tBuffer[tIdx+3] += sR * nw; tBuffer[tIdx+4] += sG * nw; tBuffer[tIdx+5] += sB * nw;
                nw = nwy * wx;
                tBuffer[tIdx+3 * tw+0] += sR * nw; tBuffer[tIdx+3 * tw+1] += sG * nw; tBuffer[tIdx+3 * tw+2] += sB * nw;
                nw = nwx * nwy;
                tBuffer[tIdx+3 * tw+3] += sR * nw; tBuffer[tIdx+3 * tw+4] += sG * nw; tBuffer[tIdx+3 * tw+5] += sB * nw;
            }
        }
    }

    var worker2Object = {'tBuffer': tBuffer}; //I guess tBuffer is too Large
        tBuffer = undefined; e = undefined;

    self.postMessage(worker2Object);   //Return to Main Thread

}, false);

当我使用 IE或FireFox (Chrome很好)时,网络工作线程中内存不足

但是当图像尺寸小于1MB时,可以在3种浏览器上工作。

因此我怀疑问题是操作的结果(tBuffer)太大。 任何人都可以帮我解决这个问题吗?谢谢你的帮助。

我需要将big-O(n ^ 2)算法移动到web worker,然后它不会阻止我的主线程来执行其他脚本。

现在,我需要在5个web worker 线程中扩展 5规格图像。程序代码

for( var i in 5 spec image size array ) { //LOOP 5 time and new 5 web workers
   //get imageData of source image
   sourceBuffer = canvas.getContext("2d").getImageData(0, 0, w, h); 

   //new Worker_1 to process spec_1 image and so on
   Worker_1 = new Worker('myWebWorker.js');
   Worker_1.postMessage(sourceBuffer);
   Worker_1.onmessage = function(e){ get e.data }
}

1 个答案:

答案 0 :(得分:2)

嗯,这是一个想法 - 当你使用Float32Array时,记住每个颜色分量从8位(1字节)大小转换为32位大小(4字节)。

因此,如果您的图像是,为简单起见,假设1000x1000,则内存消耗为:

Normal canvas:
1000 x 1000 x 4 = 4,000,000 bytes or 3.8 mb

如果是32位浮点数组,则大小为:

Float32Array:
1000 x 1000 x 16 = 16,000,000 bytes or 15.3 mb

现在将其与5相乘(假设每个工作在图像或图像上具有相同的大小),并且使用float32初始的3.8 mb画布(原始数据)将为76.5 mb。

如果你的图像更多的是在2000 x 2000的泳道中,那么你的画布为305 mb + 15 mb,或者4000 x 4000然后是1.2 gb(!)+ 61 mb的画布等等。

此外:原始大小仅适用于您可以访问的缓冲区。浏览器可能有也可能没有该数据的后台缓冲区,这意味着在后一种情况下,您将大大超过千兆字节大小,这可以很容易地解释内存不足错误消息。

如果你需要高精度的色彩处理(我假设你使用浮子),可以选择:

  • 使用16位无符号缓冲区。这会将尺寸缩小到现在的50%
  • 或者如果可能的话,使用8位缓冲区并在将结果放回缓冲区之前在浮点数中离线处理数据
  • 或使用浮动缓冲区进行分段处理,但每次只处理几行图像。

提示:如果对工作人员使用transferable objects,您将获得巨大的性能提升。