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