Skip to content

Commit 1a9fcce

Browse files
committed
Assembler // Continue patching memory management issues.
1 parent 4523934 commit 1a9fcce

File tree

1 file changed

+78
-18
lines changed

1 file changed

+78
-18
lines changed

Sources/Megrez/2_Assembler.swift

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,16 @@ extension Megrez.Compositor {
128128
let sortedStates = visited.sorted { $0.distance > $1.distance }
129129
let statesToRemove = Array(sortedStates.dropFirst(keepRecentCount))
130130

131-
// 先從 Set 中移除,再清理參據(避免 hash 不一致)
131+
// 先從 Set 中移除(避免 hash 不一致)
132132
for state in statesToRemove {
133133
visited.remove(state)
134-
state.node = nil
135-
state.prev = nil
136134
}
135+
136+
// 採用鏈條逆向清理策略清理要移除的狀態
137+
Self.cleanSearchStateChains(allStates: Set(statesToRemove))
137138
}
138139

139-
/// 即時清理策略:直接清理各個資料結構,避免額外的 Set 集合
140+
/// 即時清理策略:採用鏈條逆向清理避免循環引用
140141
/// - Parameters:
141142
/// - visited: 已訪問的狀態集合
142143
/// - openSet: 優先序列中剩餘的狀態
@@ -146,23 +147,33 @@ extension Megrez.Compositor {
146147
openSet: inout HybridPriorityQueue<PrioritizedState>,
147148
leadingState: SearchState
148149
) {
149-
// 策略1: 直接清理 visited set 中的所有狀態
150+
// 收集所有需要清理的 SearchState 物件
151+
var allStates = Set<SearchState>()
152+
153+
// 1. 新增 visited set 中的所有狀態
150154
for state in visited {
151-
state.node = nil
152-
state.prev = nil
155+
allStates.insert(state)
153156
}
154157

155-
// 策略2: 直接清理 openSet 中剩餘的所有狀態
158+
// 2. 新增 openSet 中剩餘的所有狀態
156159
while !openSet.isEmpty {
157160
if let prioritizedState = openSet.dequeue() {
158-
prioritizedState.state.node = nil
159-
prioritizedState.state.prev = nil
161+
allStates.insert(prioritizedState.state)
160162
}
161163
}
162164

163-
// 策略3: 清理 leadingState
164-
leadingState.node = nil
165-
leadingState.prev = nil
165+
// 3. 新增 leadingState
166+
allStates.insert(leadingState)
167+
168+
// 4. 採用鏈條逆向清理策略
169+
Self.cleanSearchStateChains(allStates: allStates)
170+
}
171+
172+
/// 採用 SearchState 自身的清理方法進行批次清理
173+
/// - Parameter allStates: 所有需要清理的狀態集合
174+
private static func cleanSearchStateChains(allStates: Set<SearchState>) {
175+
// 使用 SearchState 的靜態批次清理方法
176+
SearchState.batchClean(Array(allStates))
166177
}
167178
}
168179

@@ -196,9 +207,9 @@ extension Megrez.Compositor {
196207

197208
// MARK: Internal
198209

199-
var node: Megrez.Node? // 當前節點(可變,用於清理)
210+
weak var node: Megrez.Node? // 當前節點(可變,用於清理)
200211
let position: Int // 在輸入串中的位置
201-
var prev: SearchState? // 前一個狀態
212+
weak var prev: SearchState? // 前一個狀態
202213
var distance: Double // 累計分數
203214

204215
// MARK: - Hashable 協定實作
@@ -207,13 +218,62 @@ extension Megrez.Compositor {
207218
lhs.originalNodeRef === rhs.originalNodeRef && lhs.position == rhs.position
208219
}
209220

210-
/// 清理單一 SearchState 的參據
211-
/// 注意:由於新的清理策略是直接清理各個集合,這個方法現在主要用於向下相容
212-
func cleanState() {
221+
/// 靜態方法:批次清理多個 SearchState
222+
static func batchClean(_ states: [SearchState]) {
223+
var visited = Set<ObjectIdentifier>()
224+
225+
for state in states {
226+
let stateId = ObjectIdentifier(state)
227+
guard !visited.contains(stateId) else { continue }
228+
229+
// 清理此狀態及其鏈條
230+
state.cleanChainRecursively()
231+
232+
// 標記整個鏈條為已處理
233+
var current: SearchState? = state
234+
while let currentState = current {
235+
visited.insert(ObjectIdentifier(currentState))
236+
current = currentState.prev
237+
}
238+
}
239+
}
240+
241+
/// 清理自身的所有引用,立即釋放記憶體
242+
func cleanSelf() {
213243
node = nil
214244
prev = nil
215245
}
216246

247+
/// 清理整個 SearchState 鏈條,從當前節點開始向後遞歸清理
248+
/// 採用深度優先遍歷策略,確保每個節點都被清理
249+
func cleanChainRecursively() {
250+
var visited = Set<ObjectIdentifier>()
251+
var stack = [Self]()
252+
stack.append(self)
253+
254+
while !stack.isEmpty {
255+
let current = stack.removeLast()
256+
let currentId = ObjectIdentifier(current)
257+
258+
// 避免重複清理和無限循環
259+
guard !visited.contains(currentId) else { continue }
260+
visited.insert(currentId)
261+
262+
// 在清理前,將 prev 加入堆疊(如果存在)
263+
if let prevState = current.prev {
264+
stack.append(prevState)
265+
}
266+
267+
// 清理當前節點
268+
current.cleanSelf()
269+
}
270+
}
271+
272+
/// 向下相容的清理方法
273+
func cleanState() {
274+
cleanSelf()
275+
}
276+
217277
func hash(into hasher: inout Hasher) {
218278
hasher.combine(stableHash)
219279
}

0 commit comments

Comments
 (0)