WebSocket 频繁使用 onmessage 的零拷贝

12

我有一个应用程序,它经常(至少每帧一次)通过WebSocket接收二进制消息并绘制数据,使用canvas/webgl。我注意到我的内存占用呈锯齿状;有很多短暂的数据块。

enter image description here

这不让我感到惊讶,因为我每16ms至少从onmessage接收一个对象,并用于绘图,然后取消引用。

我的问题是:有没有什么方法可以避免/最小化这种情况?根据WebSocket API,似乎没有替代方案可以在每个套接字接收调用时分配新的内存。在另一种语言/环境中,我会预先分配一些内存并将其接收到该缓冲区中,以避免为短暂的对象不断分配内存,但我无法想出在JavaScript中在浏览器中实现这一点的明显方法。

供参考,这是我的“Frames”视图。

enter image description here

我不知道那段空闲时间是否是垃圾回收?任何开发工具专家的见解都将不胜感激。


你有任何代码示例吗?已经开始了什么吗?一个fiddle? - Anonymous0day
1
我也遇到了从我的树莓派通过WebSockets流传感器数据的同样问题。恐怕在JavaScript中干预WebSockets的内存分配是不可能的,现在也没有办法。我的研究并没有带来任何结果。 - windm
你希望实现什么目标?程序运行多长时间,一致、持久的性能有多重要?如果能看到一些代码或代码示例就太好了。 - Isaac Madwed
海浪上的牙齿有多高?如果你说的是5MB,那没问题,但如果是500MB,那就需要修复了。同时发布你的渲染管道,我敢打赌有一些对象可以避免被创建(稍后再收集),通常来自于意想不到的地方,比如[].map/filter()。你需要每秒钟这60个微小的对象,但它们不应该很重,可能还有其他问题... - dandavis
1
(259172488-274765862).toLocaleString() 显示了一个 15MB 的范围,对于这样一个重量级的应用程序来说其实并不算太糟糕,并且没有随时间稳步增加。总之,看起来还是很好的;Chrome 使用了相当数量的内存;即使在这个页面上也使用了64MB,因此即使有23%的波动也是有趣但不会引起警觉的,并且它也没有在每分钟做成千上万件事情... - dandavis
显示剩余2条评论
1个回答

1

我不确定我是否理解了你的问题,但是你可以像其他语言一样声明全局数组,并将其用作循环缓冲区,例如:

var buffer = [];
var bufferLength = 1000;
var start = 0;
var end = 0;
var content = 0;

socket.onmessage(function(msg) { //msg allocated
    end %= bufferLength;
    if (end == start && content != 0)
        console.log("Buffer is full");
    else {
        content++;
        buffer[end++] = msg; //reference to msg saved so it's not destroyed at the end of the callback
    }
});

function getNext() {
    start %= bufferLength;
    if (start == end && content == 0)
        console.log("Buffer is empty");
    else {
        content--;
        return buffer[start++]; // returns reference to next msg
    }
}

编辑:我修改了答案,以更清晰地解释内存循环:

JS将为WebSockets上收到的消息分配内存,并创建一个称为msg的引用,该引用将作为参数在为onmessage定义的回调中提供给您。

请注意,只有当代码中不再引用该内存块时,JS GC才会销毁该内存块。

我所做的是将该引用保存在缓冲区中,因此当回调完成并且您可以使用getNext访问它时,该值不会被销毁。您不需要分配新的内存,因为JS已经为您分配了。

如果您想克隆或创建msg的不同副本,则有一些不同的选项。一个简单的选项是克隆非循环JSON对象:

var newJSON = JSON.parse(JSON.stringify(msg));

您可以在https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management中找到有关JS内存分配的更多信息。


这并没有回答我的问题,我的问题具体与“每个套接字接收调用都会分配新的内存”有关。 - sethro
我特别关注传递给onmessage的对象msg分配的内存。我认为你误解了我的问题。我正在寻找一种预先分配缓冲区的方法,WebSocket或其他API将使用它从底层套接字接收数据。 - sethro
1
好的,我现在明白你的问题了。我认为你无法使用JS解决这个问题。你可以尝试在Chrome中启用零拷贝光栅化器来减轻一些总延迟,以便在WebGL中更快地渲染,地址是chrome://flags/#enable-zero-copy。此外,考虑到你的问题与内存访问有关,你可以尝试调整从服务器发送的数据包数量/大小,较少/较大的数据包将减少操作次数。 - Javier Conde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接