WebSocket 频繁 onmessage 零拷贝

Posted

技术标签:

【中文标题】WebSocket 频繁 onmessage 零拷贝【英文标题】:WebSocket frequent onmessage zero-copy 【发布时间】:2015-11-03 22:41:38 【问题描述】:

我有一个应用程序通过 WebSocket 频繁接收二进制消息(每帧至少一次)并使用 canvas/webgl 绘制数据。我注意到我有一个非常好的锯齿形记忆配置文件。大量短暂的数据块。

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

我的问题是:有什么技巧可以避免/减少这种情况吗?基于WebSocket API,似乎没有替代在每个套接字接收调用上分配新内存的替代方法。在另一种语言/环境中,我会预先分配一些内存并接收到该缓冲区,以避免不断为短期对象分配内存,但我想不出任何明显的方法可以在浏览器中的 javascript 中实现这一点。

作为参考,这是我的 Frames 视图。

不知道那段空闲时间算不算垃圾回收?任何开发工具忍者的见解将不胜感激。

【问题讨论】:

你有任何代码示例吗?已经开始了?小提琴? 我在通过 WebSockets 从我的树莓派流式传输传感器日期时遇到了同样的问题。恐怕有也不会干扰javascript中WebSockets的内存分配。我的研究没有带来任何结果。 你希望达到什么目标?程序运行多长时间以及一致的长期性能有多重要?看到一点代码或代码示例会很棒 我的问题是针对其他必须解决类似问题的人:经常接收大量异步数据。 WebSocket 似乎没有提供任何在套接字接收级别(零拷贝)管理内存的方法。我知道有一些应用程序具有这个基本功能:有没有办法更聪明地在浏览器中复制内存? (259172488-274765862).toLocaleString() 显示 15mb 范围。对于这么重的应用程序来说,这实际上并没有那么糟糕,并且随着时间的推移没有稳定的增长。简而言之,它看起来还不错; chrome 使用了大量的内存;即使是这个页面也使用 64mb,所以即使在上面,23% 的摆动也会很有趣但并不令人担忧,而且它并不是每分钟做数千件事...... 【参考方案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中内存分配的信息

【讨论】:

这没有回答我的问题,特别是关于“在每个套接字接收调用上分配的新内存”。 我特别关心为传递给onmessage的对象分配的内存:msg。我想你误解了我的问题。我正在寻求一种方法来预先分配一个缓冲区,WebSocket 或其他一些 API 将使用该缓冲区来从底层套接字接收数据。 好的,我现在明白你的问题了。我不认为你可以用 JS 做任何事情。您可能能够减轻在 chrome 中启用零复制光栅化器的一些总延迟 chrome://flags/#enable-zero-copy 以便它在 webgl 中渲染得更快。此外,鉴于您的问题是关于内存访问的,您可以使用从服务器发送的数据包的数量/大小,更少/更大的数据包将减少操作数。

以上是关于WebSocket 频繁 onmessage 零拷贝的主要内容,如果未能解决你的问题,请参考以下文章

Java WebSocket:onMessage 未触发

不同的 WebSocket“onmessage”处理程序取决于屏幕

C# 创建 websocket - onmessage 函数不起作用

onMessage WebSocket 中的消息处理

Glassfish websocket OnMessage方法突然退出

Vue.js 在 websocket onmessage 事件中更新 html