source: Include/system/gc.sbp@ 144

Last change on this file since 144 was 144, checked in by dai, 17 years ago

GCを参照型オブジェクトに適用。
未解放のメモリオブジェクトのダンプ処理をgc.sbpに実装したので、DumpMemoryLeaks.abは破棄した。

File size: 11.3 KB
Line 
1/*
2 このファイルでは、ABのガベージコレクションの実装を行います。
3*/
4
5
6/*
7※これらの変数はコンパイラが自動的に定義します。
8Dim _System_gc_GlobalRoot_StartPtr As VoidPtr
9Dim _System_gc_GlobalRoot_Size As Long
10Dim _System_gc_StackRoot_StartPtr As VoidPtr
11*/
12
13Function _System_GetSp() As LONG_PTR 'dummy
14End Function
15
16
17Const _System_GC_FLAG_ATOMIC = 1
18Const _System_GC_FLAG_NEEDFREE = 2
19Const _System_GC_FLAG_INITZERO = 4
20Const _System_GC_FLAG_OBJECT = 8
21
22Const THREAD_GET_CONTEXT = &H0008
23
24Class _System_CGarbageCollection
25 ppPtr As *VoidPtr
26 pSize As *SIZE_T
27 pdwFlags As *DWord
28 n As Long
29
30 iAllSize As SIZE_T
31
32 isSweeping As Boolean
33
34 CriticalSection As CRITICAL_SECTION
35
36 'メモリの上限値(この値を超えるとGCが発動します)
37 '※バイト単位
38 limitMemorySize As LONG_PTR
39
40 isFinish As Boolean
41
42Public
43
44 ' 特殊クラスのため、コンストラクタ・デストラクタは呼ばれません
45 Sub _System_CGarbageCollection()
46 End Sub
47 Sub ~_System_CGarbageCollection()
48 End Sub
49
50 Sub Begin()
51 If ppPtr Then Exit Sub
52
53 isFinish = False
54
55 'メモリの上限値(この値を超えるとGCが発動します)
56 '※バイト単位
57 limitMemorySize = 1024*1024 As LONG_PTR
58
59 ppPtr=_System_calloc( 1 )
60 pSize=_System_calloc( 1 )
61 pdwFlags=_System_calloc( 1 )
62 n=0
63
64 iAllSize=0
65
66 ' スウィープ中かどうか
67 isSweeping = False
68
69 'クリティカルセッションを生成
70 InitializeCriticalSection(CriticalSection)
71
72
73 '---------------------------
74 ' 開始時のスレッドを通知
75 '---------------------------
76 Dim hTargetThread As HANDLE
77 DuplicateHandle(GetCurrentProcess(),
78 GetCurrentThread(),
79 GetCurrentProcess(),
80 hTargetThread, 0, FALSE, DUPLICATE_SAME_ACCESS) 'カレントスレッドのハンドルを複製
81
82 ' スレッド管理用オブジェクトを生成
83 _System_pobj_AllThreads = New _System_CThreadCollection()
84
85 ' 自身のThreadオブジェクトを生成
86 Dim thread As Thread(hTargetThread,GetCurrentThreadId(),0)
87
88 _System_pobj_AllThreads->BeginThread(VarPtr( thread ),_System_gc_StackRoot_StartPtr As *LONG_PTR)
89
90 End Sub
91 Sub Finish()
92 If ppPtr=0 Then Exit Sub
93
94 isFinish = True
95
96 ' スレッド管理用オブジェクトを破棄
97 Delete _System_pobj_AllThreads
98
99 ' 自分以外のスレッドを一時停止
100 '_System_pobj_AllThreads->SuspendAnotherThread()
101
102 OutputDebugString( Ex"garbage colletion sweeping all memory objects!\r\n" )
103 DeleteAllGarbageMemories()
104
105 ' 未解放のメモリオブジェクトをトレース
106 DumpMemoryLeaks()
107
108 ' 自分以外のスレッドを再開
109 '_System_pobj_AllThreads->ResumeAnotherThread()
110
111 HeapFree(_System_hProcessHeap,0,ppPtr)
112 ppPtr=0
113
114 HeapFree(_System_hProcessHeap,0,pSize)
115 pSize=0
116 HeapFree(_System_hProcessHeap,0,pdwFlags)
117 pdwFlags=0
118
119 'クリティカルセッションを破棄
120 DeleteCriticalSection(CriticalSection)
121
122 End Sub
123
124 Sub add(new_ptr As VoidPtr, size As SIZE_T,flags As DWord)
125 iAllSize+=size
126
127 EnterCriticalSection(CriticalSection)
128 ppPtr=HeapReAlloc(_System_hProcessHeap,0,ppPtr,(n+1)*SizeOf(VoidPtr))
129 ppPtr[n]=new_ptr
130
131 pSize=HeapReAlloc(_System_hProcessHeap,0,pSize,(n+1)*SizeOf(SIZE_T))
132 pSize[n]=size
133
134 pdwFlags=HeapReAlloc(_System_hProcessHeap,0,pdwFlags,(n+1)*SizeOf(DWord))
135 pdwFlags[n]=flags
136 LeaveCriticalSection(CriticalSection)
137
138 n++
139 End Sub
140
141
142 Function __malloc(size As SIZE_T,flags As Byte) As VoidPtr
143 EnterCriticalSection(CriticalSection)
144 Dim dwFlags As DWord
145 If flags and _System_GC_FLAG_INITZERO Then
146 dwFlags=HEAP_ZERO_MEMORY
147 Else
148 dwFlags=0
149 End If
150
151 Dim ptr = HeapAlloc(_System_hProcessHeap,dwFlags,size)
152 add( ptr, size, flags )
153 LeaveCriticalSection(CriticalSection)
154
155 Return ptr
156 End Function
157
158 Function __realloc(lpMem As VoidPtr, size As SIZE_T) As VoidPtr
159 EnterCriticalSection(CriticalSection)
160 Dim i As Long
161 For i=0 To ELM(n)
162 If ppPtr[i]=lpMem Then
163 iAllSize+=size-pSize[i]
164
165 pSize[i]=size
166 ppPtr[i]=HeapReAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,lpMem,size)
167
168 LeaveCriticalSection(CriticalSection)
169 Return ppPtr[i]
170 End If
171 Next
172 LeaveCriticalSection(CriticalSection)
173 Return 0
174 End Function
175
176 Sub __free_ex(lpMem As VoidPtr, isSweeping As Boolean)
177 EnterCriticalSection(CriticalSection)
178 Dim i As Long
179 For i=0 To ELM(n)
180 If ppPtr[i]=lpMem Then
181 If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 or isSweeping Then
182 iAllSize-=pSize[i]
183
184 HeapFree(_System_hProcessHeap,0,ppPtr[i])
185 ppPtr[i]=0
186 pSize[i]=0
187 Else
188 If isFinish = False Then
189 OutputDebugString( Ex"heap free missing!\r\n" )
190 End If
191 End If
192 End If
193 Next
194 LeaveCriticalSection(CriticalSection)
195 End Sub
196
197 Sub __free(lpMem As VoidPtr)
198 __free_ex( lpMem, False )
199 End Sub
200
201 Sub sweep()
202 EnterCriticalSection(CriticalSection)
203 If iAllSize<limitMemorySize Then
204 'メモリ使用量が上限値を超えていないとき
205 LeaveCriticalSection(CriticalSection)
206 Exit Sub
207 End If
208
209 OutputDebugString( Ex"garbage colletion sweep start!\r\n" )
210
211 Dim hThread As HANDLE
212 Dim ThreadId As DWord
213 hThread=_beginthreadex(NULL,0,AddressOf(SweepOnOtherThread),VarPtr(This),0,ThreadId)
214 WaitForSingleObject(hThread,INFINITE)
215 CloseHandle(hThread)
216 LeaveCriticalSection(CriticalSection)
217 End Sub
218
219Private
220
221 ' 生存検知
222 Function HitTest(pSample As VoidPtr) As Long
223 Dim i As Long
224 For i=0 To ELM(n)
225 If (ppPtr[i] As LONG_PTR)<=(pSample As LONG_PTR) and (pSample As LONG_PTR)<((ppPtr[i] As LONG_PTR)+pSize[i]) Then
226 Return i
227 End If
228 Next
229 Return -1
230 End Function
231
232 ' 指定領域のスキャン
233 Sub Scan(pStartPtr As *LONG_PTR, size As LONG_PTR, pbMark As *Byte)
234 Dim i As Long, count As Long, index As Long
235 count=(size\SizeOf(LONG_PTR)) As Long
236 For i=0 To ELM(count)
237 index=HitTest(pStartPtr[i] As VoidPtr)
238 If index<>-1 Then
239 If pbMark[index]=0 Then
240 pbMark[index]=1
241
242 If (pdwFlags[index] and _System_GC_FLAG_ATOMIC)=0 Then
243 'ヒープ領域がポインタ値を含む可能性があるとき
244 If ppPtr[index] = 0 Then
245 'エラー
246
247 End If
248 Scan(ppPtr[index] As *LONG_PTR,pSize[index],pbMark)
249 End If
250 End If
251 End If
252 Next
253 End Sub
254
255 ' ローカル領域をルートに指定してスキャン
256 Sub LocalScan( pbMark As *Byte )
257 Dim Context As CONTEXT
258 Dim NowSp As *LONG_PTR
259 Dim size As LONG_PTR
260 Dim i As Long
261 For i=0 To ELM(_System_pobj_AllThreads->ThreadNum)
262 If _System_pobj_AllThreads->ppobj_Thread[i] Then
263 FillMemory(VarPtr(Context),SizeOf(CONTEXT),0)
264 Context.ContextFlags=CONTEXT_CONTROL
265 If _System_pobj_AllThreads->ppobj_Thread[i]->__GetContext(Context)=0 Then
266 OutputDebugString(Ex"レジスタ情報の取得に失敗しました。\r\n")
267 End If
268
269#ifdef _WIN64
270 NowSp=Context.Rsp As *LONG_PTR
271#else
272 NowSp=Context.Esp As *LONG_PTR
273#endif
274
275 size=(_System_pobj_AllThreads->pStackBase[i] As LONG_PTR)-(NowSp As LONG_PTR)
276
277 If NowSp = 0 Then
278 debug
279 Exit Sub
280 End If
281
282 Scan( NowSp, size, pbMark )
283 End If
284 Next
285 End Sub
286
287 Sub DeleteGarbageMemories( pbMark As *Byte )
288
289 Dim isAllDelete = False
290 If pbMark = NULL Then
291 ' すべてを破棄するとき
292 isAllDelete = True
293 pbMark = _System_calloc( n )
294 End If
295
296 Dim i As Long
297 For i=0 To ELM(n)
298 If pbMark[i]=0 and ppPtr[i]<>0 and (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)=0 Then
299 If ppPtr[i] = 0 Then
300 If isAllDelete Then
301 Continue
302 Else
303 debug
304 End If
305 End If
306
307 Dim ptr = ppPtr[i]
308 Dim size = pSize[i]
309
310 ppPtr[i]=0
311 pSize[i]=0
312
313 If (pdwFlags[i] and _System_GC_FLAG_OBJECT) <> 0 Then
314 /* ・オブジェクトの個数
315 ・オブジェクトのサイズ
316 ・デストラクタの関数ポインタ
317 を考慮 */
318 _System_SweepingDelete (ptr + SizeOf( LONG_PTR ) * 3 )
319 Else
320 iAllSize-=size
321 HeapFree(_System_hProcessHeap,0,ptr)
322 End If
323 End If
324 Next
325
326 If isAllDelete Then
327 _System_free( pbMark )
328 End If
329
330 End Sub
331
332 Sub DeleteAllGarbageMemories()
333 DeleteGarbageMemories( NULL )
334 End Sub
335
336 Sub Compaction()
337 Dim i As Long, i2 = 0 As Long
338 For i=0 To ELM(n)
339 ppPtr[i2] = ppPtr[i]
340 pSize[i2] = pSize[i]
341 pdwFlags[i2] = pdwFlags[i]
342
343 If ppPtr[i] Then
344 i2++
345 End If
346 Next
347 n = i2
348 End Sub
349
350 ' スウィープ(新規スレッドで呼び出し)
351 Function Cdecl SweepOnOtherThread() As Long
352
353 ' すべてのスレッドを一時停止
354 _System_pobj_AllThreads->SuspendAllThread()
355
356 ' マークリストを生成
357 Dim pbMark = HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,n*SizeOf(Byte)) As *Byte
358
359 ' グローバル領域をルートに指定してスキャン
360 Scan( _System_gc_GlobalRoot_StartPtr, _System_gc_GlobalRoot_Size, pbMark )
361
362 ' ローカル領域をルートに指定してスキャン
363 LocalScan( pbMark )
364
365 ' スウィープ前のメモリサイズを退避
366 Dim iBackAllSize = iAllSize
367
368 ' スウィープ前のメモリオブジェクトの数
369 Dim iBeforeN = n
370
371 '使われていないメモリを解放する
372 DeleteGarbageMemories(pbMark)
373
374 'コンパクション
375 Compaction()
376
377 'マークリストを解放
378 HeapFree(_System_hProcessHeap,0,pbMark)
379
380 If iBackAllSize=iAllSize Then
381 If iAllSize > limitMemorySize Then
382 limitMemorySize = iAllSize
383 End If
384
385 '許容量を拡張する
386 limitMemorySize *= 2
387
388 OutputDebugString( Ex"memory size is extended for gc!\r\n" )
389 End If
390
391 Dim temp[100] As Char
392 wsprintf(temp,Ex"object items ... %d -> %d ( %dMB -> %dMB )\r\n",iBeforeN,n, iBackAllSize\1024\1024, iAllSize\1024\1024)
393 OutputDebugString( temp )
394 wsprintf(temp,Ex"limit size of memory ... %d\r\n",limitMemorySize)
395 OutputDebugString( temp )
396 OutputDebugString( Ex"garbage colletion sweep finish!\r\n" )
397
398
399 '-------------------------------------
400 ' すべてのスレッドを再開
401 '-------------------------------------
402 _System_pobj_AllThreads->ResumeAllThread()
403 End Function
404
405 ' 未解放のメモリオブジェクトをトレース
406 Sub DumpMemoryLeaks()
407 Dim isLeak = False
408 Dim i As Long
409 For i=0 To ELM(n)
410 If ppPtr[i] Then
411 If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 Then
412 If isLeak = False Then
413 OutputDebugString( Ex"Detected memory leaks!\r\n" )
414 isLeak = True
415 End If
416
417 Dim temp[100] As Char
418 OutputDebugString( Ex"heap free missing!\r\n" )
419 wsprintf(temp,Ex"{%d} normal block at &H%08X, %d bytes long.\r\n", i, ppPtr[i], pSize[i])
420 OutputDebugString( temp )
421 End If
422 End If
423 Next
424
425 If isLeak Then
426 OutputDebugString( Ex"Object dump complete.\r\n" )
427 End If
428
429 End Sub
430
431End Class
432
433'GC管理用の特殊なシステムオブジェクト(デストラクタは最終のタイミングで呼び出されます)
434Dim _System_pGC As *_System_CGarbageCollection
435
436
437
438Function GC_malloc(size As Long) As VoidPtr
439 ' sweep
440 _System_pGC->sweep()
441
442 'allocate
443 Return _System_pGC->__malloc(size,0)
444End Function
445
446Function GC_malloc_atomic(size As Long) As VoidPtr
447 ' sweep
448 _System_pGC->sweep()
449
450 'allocate
451 Return _System_pGC->__malloc(size,_System_GC_FLAG_ATOMIC)
452End Function
453
454Function _System_GC_malloc_ForObject(size As Long) As VoidPtr
455 ' sweep
456 _System_pGC->sweep()
457
458 'allocate
459 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO)
460End Function
461
462Function _System_GC_malloc_ForObjectPtr(size As Long) As VoidPtr
463 ' sweep
464 _System_pGC->sweep()
465
466 'allocate
467 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO or _System_GC_FLAG_NEEDFREE)
468End Function
469
470Function _System_GC_free_for_SweepingDelete( ptr As *Object )
471 ' free
472 _System_pGC->__free_ex( ptr, True )
473End Function
Note: See TracBrowser for help on using the repository browser.