Skip to content

Commit 0dccadc

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

File tree

1 file changed

+83
-18
lines changed

1 file changed

+83
-18
lines changed

Sources/Megrez/2_Assembler.swift

Lines changed: 83 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,65 @@ 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+
/// 採用鏈條逆向清理策略,從最遠端的 prev 開始逐一退行清理
173+
/// - Parameter allStates: 所有需要清理的狀態集合
174+
private static func cleanSearchStateChains(allStates: Set<SearchState>) {
175+
var processedStates = Set<SearchState>()
176+
177+
// 對每個狀態進行鏈條逆向清理
178+
for state in allStates {
179+
guard !processedStates.contains(state) else { continue }
180+
181+
// 找到鏈條的末端(最遠端的 prev)
182+
var chainStates = [SearchState]()
183+
var current: SearchState? = state
184+
185+
// 追溯整個鏈條,收集所有狀態
186+
while let currentState = current {
187+
// 避免無限循環(檢測循環引用)
188+
if chainStates.contains(where: { $0 === currentState }) {
189+
break
190+
}
191+
chainStates.append(currentState)
192+
current = currentState.prev
193+
}
194+
195+
// 從鏈條末端開始逐一清理(逆向清理)
196+
for i in stride(from: chainStates.count - 1, through: 0, by: -1) {
197+
let stateToClean = chainStates[i]
198+
199+
// 首先清理 node 引用
200+
stateToClean.node = nil
201+
202+
// 然後清理 prev 引用(從末端開始,確保沒有懸掛指針)
203+
stateToClean.prev = nil
204+
205+
// 標記為已處理
206+
processedStates.insert(stateToClean)
207+
}
208+
}
166209
}
167210
}
168211

@@ -196,9 +239,9 @@ extension Megrez.Compositor {
196239

197240
// MARK: Internal
198241

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

204247
// MARK: - Hashable 協定實作
@@ -207,11 +250,33 @@ extension Megrez.Compositor {
207250
lhs.originalNodeRef === rhs.originalNodeRef && lhs.position == rhs.position
208251
}
209252

210-
/// 清理單一 SearchState 的參據
253+
/// 清理單一 SearchState 的參據,採用鏈條逆向清理策略
211254
/// 注意:由於新的清理策略是直接清理各個集合,這個方法現在主要用於向下相容
212255
func cleanState() {
213-
node = nil
214-
prev = nil
256+
// 對於單一狀態,我們使用簡化的鏈條清理
257+
var chainStates = [Self]()
258+
var current: SearchState? = self
259+
260+
// 追溯整個鏈條,收集所有狀態
261+
while let currentState = current {
262+
// 避免無限循環(檢測循環引用)
263+
if chainStates.contains(where: { $0 === currentState }) {
264+
break
265+
}
266+
chainStates.append(currentState)
267+
current = currentState.prev
268+
}
269+
270+
// 從鏈條末端開始逐一清理(逆向清理)
271+
for i in stride(from: chainStates.count - 1, through: 0, by: -1) {
272+
let stateToClean = chainStates[i]
273+
274+
// 首先清理 node 引用
275+
stateToClean.node = nil
276+
277+
// 然後清理 prev 引用(從末端開始,確保沒有懸掛指針)
278+
stateToClean.prev = nil
279+
}
215280
}
216281

217282
func hash(into hasher: inout Hasher) {

0 commit comments

Comments
 (0)