source: Include/system/gc.sbp@ 214

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

GCでのメモリ回収処理を、実行時型情報を元に行うようにした。

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