source: Include/system/gc.sbp@ 259

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

リリースコンパイル時にGC及び動的型情報に関するデバッグ出力を行わないようにした。

File size: 13.6 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(ObjPtr( 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 _System_DebugOnly_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 _System_DebugOnly_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 Return Object.ReferenceEquals(object, Nothing)
248 End Function
249
250 ' 生存検知
251 Function HitTest(pSample As VoidPtr) As Long
252 Dim i As Long
253 For i=0 To ELM(n)
254 If (ppPtr[i] As LONG_PTR)<=(pSample As LONG_PTR) and (pSample As LONG_PTR)<((ppPtr[i] As LONG_PTR)+pSize[i]) Then
255 Return i
256 End If
257 Next
258 Return -1
259 End Function
260
261 ' オブジェクトのスキャン
262 Function ScanObject(pObject As *Object, pbMark As *Byte) As Boolean
263 Dim classTypeInfo = Nothing As _System_TypeForClass
264 classTypeInfo = pObject->GetType() As _System_TypeForClass
265
266 If IsNull( classTypeInfo ) Then
267 Return False
268 End If
269
270 Dim i As Long
271 For i = 0 To ELM(classTypeInfo.numOfReference)
272 Scan( (pObject + classTypeInfo.referenceOffsets[i]) As *LONG_PTR, 1, pbMark )
273 Next
274
275 Return True
276 End Function
277
278 ' 指定領域のスキャン
279 Sub Scan(pStartPtr As *LONG_PTR, maxNum As Long, pbMark As *Byte)
280 Dim i As Long, index As Long
281
282 For i=0 To ELM(maxNum)
283 index=HitTest(pStartPtr[i] As VoidPtr)
284 If index<>-1 Then
285 If pbMark[index]=0 Then
286 pbMark[index]=1
287
288 If pdwFlags[index] and _System_GC_FLAG_OBJECT Then
289 ' オブジェクトの場合
290 If ScanObject( (ppPtr[index] + 4*SizeOf(LONG_PTR)) As *Object, pbMark) = False Then
291 Dim maxNum = (pSize[index]\SizeOf(LONG_PTR)) As Long
292 Scan(ppPtr[index] As *LONG_PTR, maxNum, pbMark)
293 End If
294
295 ElseIf (pdwFlags[index] and _System_GC_FLAG_ATOMIC)=0 Then
296 ' ヒープ領域がポインタ値を含む可能性があるとき
297 If ppPtr[index] = 0 Then
298 'エラー
299
300 End If
301
302 Dim maxNum = (pSize[index]\SizeOf(LONG_PTR)) As Long
303 Scan(ppPtr[index] As *LONG_PTR, maxNum, pbMark)
304 End If
305 End If
306 End If
307 Next
308 End Sub
309
310 ' ローカル領域をルートに指定してスキャン
311 Sub LocalScan( pbMark As *Byte )
312 Dim Context As CONTEXT
313 Dim NowSp As *LONG_PTR
314 Dim size As LONG_PTR
315 Dim i As Long
316 For i=0 To ELM(_System_pobj_AllThreads->ThreadNum)
317 If _System_pobj_AllThreads->ppobj_Thread[i] Then
318 FillMemory(VarPtr(Context),SizeOf(CONTEXT),0)
319 Context.ContextFlags=CONTEXT_CONTROL
320 If _System_pobj_AllThreads->ppobj_Thread[i]->__GetContext(Context)=0 Then
321 _System_DebugOnly_OutputDebugString(Ex"レジスタ情報の取得に失敗しました。\r\n")
322 End If
323
324#ifdef _WIN64
325 NowSp=Context.Rsp As *LONG_PTR
326#else
327 NowSp=Context.Esp As *LONG_PTR
328#endif
329
330 Dim size=(_System_pobj_AllThreads->pStackBase[i] As LONG_PTR)-(NowSp As LONG_PTR)
331 Dim maxNum = (size\SizeOf(LONG_PTR)) As Long
332
333 If NowSp = 0 Then
334 debug
335 Exit Sub
336 End If
337
338 Scan( NowSp, maxNum, pbMark )
339 End If
340 Next
341 End Sub
342
343 Sub DeleteGarbageMemories( pbMark As *Byte )
344
345 Dim isAllDelete = False
346 If pbMark = NULL Then
347 ' すべてを破棄するとき
348 isAllDelete = True
349 pbMark = _System_calloc( n )
350 End If
351
352 Dim i As Long
353 For i=0 To ELM(n)
354 If pbMark[i]=0 and ppPtr[i]<>0 and (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)=0 Then
355 If ppPtr[i] = 0 Then
356 If isAllDelete Then
357 Continue
358 Else
359 debug
360 End If
361 End If
362
363 Dim ptr = ppPtr[i]
364 Dim size = pSize[i]
365
366 ppPtr[i]=0
367 pSize[i]=0
368
369 If (pdwFlags[i] and _System_GC_FLAG_OBJECT) <> 0 Then
370 /* ・オブジェクトの個数
371 ・オブジェクトのサイズ
372 ・デストラクタの関数ポインタ
373 ・リザーブ領域
374 を考慮 */
375 _System_SweepingDelete (ptr + SizeOf( LONG_PTR ) * 4 )
376 Else
377 HeapFree(_System_hProcessHeap,0,ptr)
378 End If
379
380 iAllSize-=size
381 End If
382 Next
383
384 If isAllDelete Then
385 _System_free( pbMark )
386 End If
387
388 End Sub
389
390 Sub DeleteAllGarbageMemories()
391 DeleteGarbageMemories( NULL )
392 End Sub
393
394 Sub Compaction()
395 Dim i As Long, i2 = 0 As Long
396 For i=0 To ELM(n)
397 ppPtr[i2] = ppPtr[i]
398 pSize[i2] = pSize[i]
399 pdwFlags[i2] = pdwFlags[i]
400
401 If ppPtr[i] Then
402 i2++
403 End If
404 Next
405 n = i2
406 End Sub
407
408 ' スウィープ(新規スレッドで呼び出し)
409 Function Cdecl SweepOnOtherThread() As Long
410 EnterCriticalSection(CriticalSection)
411
412
413 Dim startTime = GetTickCount()
414
415 _System_DebugOnly_OutputDebugString( Ex"garbage colletion sweep start!\r\n" )
416
417
418 If isSweeping <> False or (iAllSize<limitMemorySize and n<limitMemoryObjectNum) Then
419 ExitThread(0)
420 End If
421 isSweeping = True
422
423 ' すべてのスレッドを一時停止
424 _System_pobj_AllThreads->SuspendAllThread()
425
426 ' マークリストを生成
427 Dim pbMark = HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,n*SizeOf(Byte)) As *Byte
428
429 ' グローバル領域をルートに指定してスキャン
430 Dim i As Long
431 For i = 0 To ELM( globalRootNum )
432 Scan( pGlobalRoots[i].ptr, pGlobalRoots[i].count, pbMark )
433 Next
434
435 ' ローカル領域をルートに指定してスキャン
436 LocalScan( pbMark )
437
438 ' スウィープ前のメモリサイズを退避
439 Dim iBackAllSize = iAllSize
440
441 ' スウィープ前のメモリオブジェクトの数
442 Dim iBeforeN = n
443
444 '使われていないメモリを解放する
445 DeleteGarbageMemories(pbMark)
446
447 'コンパクション
448 Compaction()
449
450 'マークリストを解放
451 HeapFree(_System_hProcessHeap,0,pbMark)
452
453 If iBackAllSize=iAllSize Then
454 If iAllSize > limitMemorySize Then
455 limitMemorySize = iAllSize
456 End If
457
458 '許容量を拡張する
459 limitMemorySize *= 2
460 limitMemoryObjectNum *= 2
461
462 _System_DebugOnly_OutputDebugString( Ex"memory size is extended for gc!\r\n" )
463 End If
464
465 Dim temp[100] As Char
466 wsprintf(temp,Ex"object items ... %d -> %d ( %d MB -> %d MB )\r\n",iBeforeN,n, iBackAllSize\1024\1024, iAllSize\1024\1024)
467 _System_DebugOnly_OutputDebugString( temp )
468 wsprintf(temp,Ex"limit size of memory ... %d\r\n",limitMemorySize)
469 _System_DebugOnly_OutputDebugString( temp )
470 wsprintf(temp,Ex"garbage colletion sweep finish! (%d ms)\r\n\r\n", GetTickCount()-startTime)
471 _System_DebugOnly_OutputDebugString( temp )
472
473
474 '-------------------------------------
475 ' すべてのスレッドを再開
476 '-------------------------------------
477 _System_pobj_AllThreads->ResumeAllThread()
478
479 LeaveCriticalSection(CriticalSection)
480 End Function
481
482 ' 未解放のメモリオブジェクトをトレース
483 Sub DumpMemoryLeaks()
484 Dim isLeak = False
485 Dim i As Long
486 For i=0 To ELM(n)
487 If ppPtr[i] Then
488 If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 Then
489 If isLeak = False Then
490 _System_DebugOnly_OutputDebugString( Ex"Detected memory leaks!\r\n" )
491 isLeak = True
492 End If
493
494 Dim temp[100] As Char
495 _System_DebugOnly_OutputDebugString( Ex"heap free missing!\r\n" )
496 wsprintf(temp,Ex"{%d} normal block at &H%08X, %d bytes long.\r\n", i, ppPtr[i], pSize[i])
497 _System_DebugOnly_OutputDebugString( temp )
498 End If
499 End If
500 Next
501
502 If isLeak Then
503 _System_DebugOnly_OutputDebugString( Ex"Object dump complete.\r\n" )
504 End If
505
506 End Sub
507
508End Class
509
510'GC管理用の特殊なシステムオブジェクト(デストラクタは最終のタイミングで呼び出されます)
511Dim _System_pGC As *_System_CGarbageCollection
512
513
514
515Function GC_malloc(size As Long) As VoidPtr
516 ' sweep
517 _System_pGC->sweep()
518
519 'allocate
520 Return _System_pGC->__malloc(size,0)
521End Function
522
523Function GC_malloc_atomic(size As Long) As VoidPtr
524 ' sweep
525 _System_pGC->sweep()
526
527 'allocate
528 Return _System_pGC->__malloc(size,_System_GC_FLAG_ATOMIC)
529End Function
530
531Function _System_GC_malloc_ForObject(size As Long) As VoidPtr
532 ' sweep
533 _System_pGC->sweep()
534
535 'allocate
536 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO)
537End Function
538
539Function _System_GC_malloc_ForObjectPtr(size As Long) As VoidPtr
540 ' sweep
541 _System_pGC->sweep()
542
543 'allocate
544 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO or _System_GC_FLAG_NEEDFREE)
545End Function
546
547Function _System_GC_free_for_SweepingDelete( ptr As *Object )
548 ' free
549 _System_pGC->__free_ex( ptr, True )
550End Function
Note: See TracBrowser for help on using the repository browser.