JavaScript-内存泄漏:主线程使用Transferable将数据传递给子线程,GC不会启动

文章讲述了在使用Transferable进行主线程与子线程数据传输时,尽管避免了复制导致的性能问题,但未正确回收子线程中的缓冲区,从而引起内存不稳定。通过排查和实验,发现需要将使用完的缓冲区传递回主线程以实现内存的正确回收,这样做之后解决了内存上涨的问题。
摘要由CSDN通过智能技术生成

        之前在主线程与子线程传递的过程中,数据较大、交互频繁。如果主线程或子线程有阻塞,则很容易造成数据堆积,导致崩溃。为了解决这一问题,于是使用了Transferable。

// 创建一个子线程
let worker = new Worker('worker.js')

// 创建一个u8a类型的数据
let data = new Unit8Array(100)

// 发送数据到子线程
worker.postMessage({
    value: data
},[data.buffer])

        这本身在一定程度上优化了内存,因为Transferable的使用并不是复制数据,而是将主线程的控制权移交给了子线程。

        但是在后期的内存测试中,发现只要数据进入子线程,内存曲线就不稳定,于是我们有了以下几种猜想:

        1、子线程内部存在内存泄漏(逐步排查后发现并没有任何问题)

        2、底层可能存在内存泄漏(底层不做任何处理直接返回数据依然存在问题,也可以排除)

        3、由于线程阻塞导致的postMessage过程中数据堆积造成内存不稳定(但是由于使用了Transferable,实际上传递的是指针,内存应该并不大也不是造成内存不稳定上涨的原因)

        

        以上的因素都已排除,但是通过一个个的模块拆分测试,确实是主线程传递到子线程就出现了内存上涨,之后的流程内存也是稳定的。

        后来查阅资料,看到有人说使用Transferable后需要再将缓冲区传递回主线程,否则可能不会回收。想了一下确实有点道理,因为主线程创建的内存空间,相当于只是移交了控制权,但本质内存空间还在主线程,但由于主线程和子线程有线程隔离,所以主线程并不知道子线程是否用完了,所以就导致不会回收。想通了这个后,就尝试了一下,果然有效。

// 创建一个空数组
let arr = []

// 接收主线程传来的消息
onmessage = (e) => {
    arr.push(e.data.value)
}

// 循环去使用数据
setInterval(() => {
    let data = arr.shift()
    // 子线程使用数据
    ....

    // 使用完了以后将缓冲区还给主线程,可以什么内容都不传,只需要缓冲区
    postMessage({
        
    },[data.buffer])
},300)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值