@@ -21,13 +21,17 @@ extension Megrez.Compositor {
2121 var visited = Set < SearchState > ( )
2222 var bestScore = [ Int: Double] ( ) // 追蹤每個位置的最佳分數
2323
24+ var stateCleaningTasks : [ ( ) -> ( ) ] = [ ]
25+ defer { stateCleaningTasks. forEach { $0 ( ) } }
26+
2427 // 初期化起始狀態。
2528 let leadingNode = Megrez . Node ( keyArray: [ " $LEADING " ] )
2629 let start = SearchState (
2730 node: leadingNode,
2831 position: 0 ,
2932 prev: nil ,
30- distance: 0
33+ distance: 0 ,
34+ cleaningTaskRegister: & stateCleaningTasks
3135 )
3236 openSet. enqueue ( PrioritizedState ( state: start) )
3337 bestScore [ 0 ] = 0
@@ -67,7 +71,8 @@ extension Megrez.Compositor {
6771 node: nextNode,
6872 position: nextPos,
6973 prev: current,
70- distance: newScore
74+ distance: newScore,
75+ cleaningTaskRegister: & stateCleaningTasks
7176 )
7277
7378 bestScore [ nextPos] = newScore
@@ -76,18 +81,17 @@ extension Megrez.Compositor {
7681
7782 // 即時記憶體最佳化:當 visited 集合過大時進行部分清理
7883 if visited. count > 1_000 { // 可調整的閾值
79- Self . partialCleanVisitedStates ( visited: & visited, keepRecentCount: 500 )
84+ // 簡單清理:保留最近的高分狀態,清理較舊的低分狀態
85+ let sortedStates = visited. sorted { $0. distance > $1. distance }
86+ let statesToRemove = Array ( sortedStates. dropFirst ( 500 ) )
87+ for state in statesToRemove {
88+ visited. remove ( state)
89+ }
8090 }
8191 }
8292
8393 // 從最佳終止狀態重建路徑。
8494 guard let finalState = bestFinalState else {
85- // 即使沒有找到最佳狀態,也需要清理所有建立的 SearchState 物件
86- Self . batchCleanAllSearchStates (
87- visited: visited,
88- openSet: & openSet,
89- leadingState: start
90- )
9195 return [ ]
9296 }
9397
@@ -103,67 +107,8 @@ extension Megrez.Compositor {
103107 // 備註:此處不需要手動 ASAN,因為沒有參據循環(Retain Cycle)。
104108 }
105109 assembledNodes = pathNodes. map ( \. copy)
106-
107- // 手動 ASAN:批次清理所有 SearchState 物件以防止記憶體洩漏
108- // 包括 visited set 中的所有狀態、openSet 中剩餘的狀態,以及 leadingState
109- Self . batchCleanAllSearchStates (
110- visited: visited,
111- openSet: & openSet,
112- leadingState: start
113- )
114110 return assembledNodes
115111 }
116-
117- /// 部分清理已訪問狀態集合以控制記憶體使用
118- /// - Parameters:
119- /// - visited: 已訪問的狀態集合
120- /// - keepRecentCount: 要保留的最近狀態數量
121- private static func partialCleanVisitedStates(
122- visited: inout Set < SearchState > ,
123- keepRecentCount: Int
124- ) {
125- guard visited. count > keepRecentCount else { return }
126-
127- // 按距離排序,保留分數較高的狀態
128- let sortedStates = visited. sorted { $0. distance > $1. distance }
129- let statesToRemove = Array ( sortedStates. dropFirst ( keepRecentCount) )
130-
131- // 先從 Set 中移除,再清理參據(避免 hash 不一致)
132- for state in statesToRemove {
133- visited. remove ( state)
134- state. node = nil
135- state. prev = nil
136- }
137- }
138-
139- /// 即時清理策略:直接清理各個資料結構,避免額外的 Set 集合
140- /// - Parameters:
141- /// - visited: 已訪問的狀態集合
142- /// - openSet: 優先序列中剩餘的狀態
143- /// - leadingState: 初始狀態
144- private static func batchCleanAllSearchStates(
145- visited: Set < SearchState > ,
146- openSet: inout HybridPriorityQueue < PrioritizedState > ,
147- leadingState: SearchState
148- ) {
149- // 策略1: 直接清理 visited set 中的所有狀態
150- for state in visited {
151- state. node = nil
152- state. prev = nil
153- }
154-
155- // 策略2: 直接清理 openSet 中剩餘的所有狀態
156- while !openSet. isEmpty {
157- if let prioritizedState = openSet. dequeue ( ) {
158- prioritizedState. state. node = nil
159- prioritizedState. state. prev = nil
160- }
161- }
162-
163- // 策略3: 清理 leadingState
164- leadingState. node = nil
165- leadingState. prev = nil
166- }
167112}
168113
169114// MARK: - 搜尋狀態相關定義
@@ -179,11 +124,13 @@ extension Megrez.Compositor {
179124 /// - position: 在輸入串中的位置。
180125 /// - prev: 前一個狀態。
181126 /// - distance: 到達此狀態的累計分數。
127+ /// - cleaningTaskRegister: 登記自毀任務池。
182128 init (
183129 node: Megrez . Node ? ,
184130 position: Int ,
185131 prev: SearchState ? ,
186- distance: Double = Double ( Int . min)
132+ distance: Double = Double ( Int . min) ,
133+ cleaningTaskRegister: inout [ ( ) -> ( ) ]
187134 ) {
188135 self . node = node
189136 self . position = position
@@ -192,13 +139,16 @@ extension Megrez.Compositor {
192139 // 使用不可變的標識符來確保 hash 一致性
193140 self . originalNodeRef = node
194141 self . stableHash = Self . computeStableHash ( node: node, position: position)
142+ cleaningTaskRegister. append { [ weak self] in
143+ self ? . cleanChainRecursively ( )
144+ }
195145 }
196146
197147 // MARK: Internal
198148
199- var node : Megrez . Node ? // 當前節點(可變,用於清理)
149+ weak var node : Megrez . Node ? // 當前節點(可變,用於清理)
200150 let position : Int // 在輸入串中的位置
201- var prev : SearchState ? // 前一個狀態
151+ weak var prev : SearchState ? // 前一個狀態
202152 var distance : Double // 累計分數
203153
204154 // MARK: - Hashable 協定實作
@@ -207,11 +157,30 @@ extension Megrez.Compositor {
207157 lhs. originalNodeRef === rhs. originalNodeRef && lhs. position == rhs. position
208158 }
209159
210- /// 清理單一 SearchState 的參據
211- /// 注意:由於新的清理策略是直接清理各個集合,這個方法現在主要用於向下相容
212- func cleanState( ) {
213- node = nil
214- prev = nil
160+ /// 清理整個 SearchState 鏈條,從當前節點開始向後遞歸清理
161+ /// 採用深度優先遍歷策略,確保每個節點都被清理
162+ func cleanChainRecursively( ) {
163+ var visited = Set < ObjectIdentifier > ( )
164+ var stack : [ SearchState ] = [ ]
165+ stack. append ( self )
166+
167+ while !stack. isEmpty {
168+ let current = stack. removeLast ( )
169+ let currentId = ObjectIdentifier ( current)
170+
171+ // 避免重複清理和無限循環
172+ guard !visited. contains ( currentId) else { continue }
173+ visited. insert ( currentId)
174+
175+ // 在清理前,將 prev 加入堆疊(如果存在)
176+ if let prevState = current. prev {
177+ stack. append ( prevState)
178+ }
179+
180+ // 清理當前節點
181+ current. node = nil
182+ current. prev = nil
183+ }
215184 }
216185
217186 func hash( into hasher: inout Hasher ) {
0 commit comments