Skip to content

Commit 490e555

Browse files
committed
perf: 修复 RingBuffer.tail() 的 O(size) 内存分配问题
tail(N) 原实现通过 snapshot() 先完整拷贝整个有效内容(最多 64MB), 再从末尾切片,导致每次 supervisor 构建上下文时都分配一块大 Buffer。 改为直接从 writePos 往回定位 N 字节的起始位置,只分配 N 字节, 与 replayFrom() 的读取逻辑一致。
1 parent f4f4026 commit 490e555

1 file changed

Lines changed: 27 additions & 4 deletions

File tree

packages/server/src/terminal/ring-buffer.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,41 @@ export class RingBuffer {
111111

112112
/**
113113
* Read the last N bytes currently retained in the buffer.
114+
* Reads directly from the circular buffer — O(N), not O(size).
114115
*/
115116
tail(bytes: number): Buffer {
116117
if (bytes <= 0) {
117118
return Buffer.alloc(0)
118119
}
119120

120-
const snapshot = this.snapshot()
121-
if (snapshot.length <= bytes) {
122-
return snapshot
121+
const validBytes = Math.min(this.totalBytes, this.size)
122+
const bytesToRead = Math.min(bytes, validBytes)
123+
124+
if (bytesToRead === 0) {
125+
return Buffer.alloc(0)
126+
}
127+
128+
let readPos = this.writePos - bytesToRead
129+
if (readPos < 0) {
130+
readPos += this.size
131+
}
132+
133+
const result = Buffer.allocUnsafe(bytesToRead)
134+
let remaining = bytesToRead
135+
let offset = 0
136+
137+
while (remaining > 0) {
138+
const availableBytes = this.size - readPos
139+
const readLength = Math.min(remaining, availableBytes)
140+
141+
this.buffer.copy(result, offset, readPos, readPos + readLength)
142+
143+
readPos = (readPos + readLength) % this.size
144+
offset += readLength
145+
remaining -= readLength
123146
}
124147

125-
return snapshot.subarray(snapshot.length - bytes)
148+
return result
126149
}
127150

128151
/**

0 commit comments

Comments
 (0)