source: Include/system/gc.sbp@ 258

Last change on this file since 258 was 249, checked in by dai, 18 years ago

[32bitコンパイラ]ByRef指定のInteger/Byte型のローカル変数に値を代入すると強制終了してしまうバグを修正。
(呼び出し単体コードも対応→)関数の戻り値オブジェクトのメンバ・メソッドを一時オブジェクトを介さずに参照できるようにした。
オブジェクトの先頭バッファのサイズを4ポインタ分に拡張した。

File size: 13.4 KB
RevLine 
[109]1/*
2 このファイルでは、ABのガベージコレクションの実装を行います。
3*/
[1]4
[109]5
[1]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
[144]20Const _System_GC_FLAG_OBJECT = 8
[1]21
[214]22Type _System_GlobalRoot
23 ptr As *LONG_PTR
24 count As Long
25End Type
26
[1]27Class _System_CGarbageCollection
[144]28 ppPtr As *VoidPtr
[1]29 pSize As *SIZE_T
[144]30 pdwFlags As *DWord
[1]31 n As Long
32
33 iAllSize As SIZE_T
34
[144]35 isSweeping As Boolean
36
[1]37 CriticalSection As CRITICAL_SECTION
38
[214]39 ' メモリの上限値(この値を超えるとGCが発動します)
40 limitMemorySize As LONG_PTR ' バイト単位
41 limitMemoryObjectNum As Long ' メモリオブジェクトの個数単位
[109]42
[144]43 isFinish As Boolean
44
45
[214]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
[144]63 ' 特殊クラスのため、コンストラクタ・デストラクタは呼ばれません
[1]64 Sub _System_CGarbageCollection()
[144]65 End Sub
66 Sub ~_System_CGarbageCollection()
67 End Sub
68
[214]69Public
70
[144]71 Sub Begin()
[1]72 If ppPtr Then Exit Sub
73
[144]74 isFinish = False
75
76 'メモリの上限値(この値を超えるとGCが発動します)
[214]77 limitMemorySize = 1024*1024 As LONG_PTR ' バイト単位
78 limitMemoryObjectNum = 2000 ' メモリオブジェクトの個数単位
[144]79
80 ppPtr=_System_calloc( 1 )
81 pSize=_System_calloc( 1 )
82 pdwFlags=_System_calloc( 1 )
[1]83 n=0
84
[214]85 ' Global Root
86 pGlobalRoots = _System_calloc( 1 )
87 globalRootNum = 0
88 RegisterGlobalRoots()
89
[1]90 iAllSize=0
91
[144]92 ' スウィープ中かどうか
93 isSweeping = False
[1]94
95 'クリティカルセッションを生成
96 InitializeCriticalSection(CriticalSection)
97
[18]98
99 '---------------------------
100 ' 開始時のスレッドを通知
101 '---------------------------
[1]102 Dim hTargetThread As HANDLE
103 DuplicateHandle(GetCurrentProcess(),
104 GetCurrentThread(),
105 GetCurrentProcess(),
106 hTargetThread, 0, FALSE, DUPLICATE_SAME_ACCESS) 'カレントスレッドのハンドルを複製
[18]107
[144]108 ' スレッド管理用オブジェクトを生成
109 _System_pobj_AllThreads = New _System_CThreadCollection()
[18]110
[144]111 ' 自身のThreadオブジェクトを生成
112 Dim thread As Thread(hTargetThread,GetCurrentThreadId(),0)
[18]113
[232]114 _System_pobj_AllThreads->BeginThread(ObjPtr( thread ),_System_gc_StackRoot_StartPtr As *LONG_PTR)
[144]115
[1]116 End Sub
[144]117 Sub Finish()
[1]118 If ppPtr=0 Then Exit Sub
119
[144]120 isFinish = True
[79]121
[144]122 ' スレッド管理用オブジェクトを破棄
123 Delete _System_pobj_AllThreads
[1]124
[144]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
[214]137 _System_free( ppPtr )
138 ppPtr = NULL
[1]139
[214]140 _System_free( pSize )
141 pSize = NULL
142 _System_free( pdwFlags )
143 pdwFlags = NULL
[1]144
[214]145 _System_free( pGlobalRoots )
146 pGlobalRoots = NULL
147
[1]148 'クリティカルセッションを破棄
149 DeleteCriticalSection(CriticalSection)
[144]150
[79]151 End Sub
[1]152
[170]153 Sub add(new_ptr As VoidPtr, size As SIZE_T, flags As DWord)
[1]154 iAllSize+=size
155
[144]156 EnterCriticalSection(CriticalSection)
157 ppPtr=HeapReAlloc(_System_hProcessHeap,0,ppPtr,(n+1)*SizeOf(VoidPtr))
158 ppPtr[n]=new_ptr
[1]159
[144]160 pSize=HeapReAlloc(_System_hProcessHeap,0,pSize,(n+1)*SizeOf(SIZE_T))
161 pSize[n]=size
[1]162
[144]163 pdwFlags=HeapReAlloc(_System_hProcessHeap,0,pdwFlags,(n+1)*SizeOf(DWord))
164 pdwFlags[n]=flags
165 LeaveCriticalSection(CriticalSection)
[1]166
167 n++
168 End Sub
169
170
171 Function __malloc(size As SIZE_T,flags As Byte) As VoidPtr
[203]172' EnterCriticalSection(CriticalSection)
[1]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
[144]180 Dim ptr = HeapAlloc(_System_hProcessHeap,dwFlags,size)
181 add( ptr, size, flags )
[203]182' LeaveCriticalSection(CriticalSection)
[1]183
[144]184 Return ptr
[1]185 End Function
186
187 Function __realloc(lpMem As VoidPtr, size As SIZE_T) As VoidPtr
[18]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]
[1]193
[18]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)
[1]202 Return 0
203 End Function
204
[144]205 Sub __free_ex(lpMem As VoidPtr, isSweeping As Boolean)
[18]206 EnterCriticalSection(CriticalSection)
207 Dim i As Long
208 For i=0 To ELM(n)
209 If ppPtr[i]=lpMem Then
[144]210 If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 or isSweeping Then
[18]211 iAllSize-=pSize[i]
[1]212
[18]213 HeapFree(_System_hProcessHeap,0,ppPtr[i])
214 ppPtr[i]=0
215 pSize[i]=0
216 Else
[144]217 If isFinish = False Then
218 OutputDebugString( Ex"heap free missing!\r\n" )
219 End If
[18]220 End If
[1]221 End If
[18]222 Next
223 LeaveCriticalSection(CriticalSection)
[1]224 End Sub
225
[144]226 Sub __free(lpMem As VoidPtr)
227 __free_ex( lpMem, False )
228 End Sub
229
[1]230 Sub sweep()
[214]231 If isSweeping <> False or (iAllSize<limitMemorySize and n<limitMemoryObjectNum) Then
[171]232 'メモリ使用量が上限値を超えていないとき
233 Exit Sub
234 End If
[144]235
[171]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)
[202]241 isSweeping = False
[1]242 End Sub
243
[144]244Private
[1]245
[214]246 Static Function IsNull( object As Object ) As Boolean
[237]247 Return Object.ReferenceEquals(object, Nothing)
[214]248 End Function
249
[144]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
[1]260
[214]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
[144]278 ' 指定領域のスキャン
[214]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)
[144]283 index=HitTest(pStartPtr[i] As VoidPtr)
284 If index<>-1 Then
285 If pbMark[index]=0 Then
286 pbMark[index]=1
[170]287
[214]288 If pdwFlags[index] and _System_GC_FLAG_OBJECT Then
289 ' オブジェクトの場合
[249]290 If ScanObject( (ppPtr[index] + 4*SizeOf(LONG_PTR)) As *Object, pbMark) = False Then
[214]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 ' ヒープ領域がポインタ値を含む可能性があるとき
[144]297 If ppPtr[index] = 0 Then
298 'エラー
[170]299
[144]300 End If
[214]301
302 Dim maxNum = (pSize[index]\SizeOf(LONG_PTR)) As Long
303 Scan(ppPtr[index] As *LONG_PTR, maxNum, pbMark)
[144]304 End If
305 End If
306 End If
307 Next
308 End Sub
[1]309
[144]310 ' ローカル領域をルートに指定してスキャン
311 Sub LocalScan( pbMark As *Byte )
[18]312 Dim Context As CONTEXT
[1]313 Dim NowSp As *LONG_PTR
314 Dim size As LONG_PTR
[18]315 Dim i As Long
316 For i=0 To ELM(_System_pobj_AllThreads->ThreadNum)
317 If _System_pobj_AllThreads->ppobj_Thread[i] Then
[1]318 FillMemory(VarPtr(Context),SizeOf(CONTEXT),0)
319 Context.ContextFlags=CONTEXT_CONTROL
[18]320 If _System_pobj_AllThreads->ppobj_Thread[i]->__GetContext(Context)=0 Then
[1]321 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
[214]330 Dim size=(_System_pobj_AllThreads->pStackBase[i] As LONG_PTR)-(NowSp As LONG_PTR)
331 Dim maxNum = (size\SizeOf(LONG_PTR)) As Long
[1]332
[144]333 If NowSp = 0 Then
334 debug
335 Exit Sub
336 End If
337
[214]338 Scan( NowSp, maxNum, pbMark )
[1]339 End If
340 Next
[144]341 End Sub
[1]342
[144]343 Sub DeleteGarbageMemories( pbMark As *Byte )
[1]344
[144]345 Dim isAllDelete = False
346 If pbMark = NULL Then
347 ' すべてを破棄するとき
348 isAllDelete = True
349 pbMark = _System_calloc( n )
350 End If
[1]351
[144]352 Dim i As Long
[1]353 For i=0 To ELM(n)
[144]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
[1]362
[144]363 Dim ptr = ppPtr[i]
364 Dim size = pSize[i]
365
[1]366 ppPtr[i]=0
367 pSize[i]=0
[144]368
369 If (pdwFlags[i] and _System_GC_FLAG_OBJECT) <> 0 Then
370 /* ・オブジェクトの個数
371 ・オブジェクトのサイズ
372 ・デストラクタの関数ポインタ
[249]373 ・リザーブ領域
[144]374 を考慮 */
[249]375 _System_SweepingDelete (ptr + SizeOf( LONG_PTR ) * 4 )
[144]376 Else
377 HeapFree(_System_hProcessHeap,0,ptr)
378 End If
[214]379
380 iAllSize-=size
[1]381 End If
382 Next
383
[144]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
[171]410 EnterCriticalSection(CriticalSection)
[144]411
[214]412
413 Dim startTime = GetTickCount()
414
415 OutputDebugString( Ex"garbage colletion sweep start!\r\n" )
416
417
418 If isSweeping <> False or (iAllSize<limitMemorySize and n<limitMemoryObjectNum) Then
[202]419 ExitThread(0)
420 End If
[203]421 isSweeping = True
[202]422
[144]423 ' すべてのスレッドを一時停止
424 _System_pobj_AllThreads->SuspendAllThread()
425
426 ' マークリストを生成
427 Dim pbMark = HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,n*SizeOf(Byte)) As *Byte
428
429 ' グローバル領域をルートに指定してスキャン
[214]430 Dim i As Long
431 For i = 0 To ELM( globalRootNum )
432 Scan( pGlobalRoots[i].ptr, pGlobalRoots[i].count, pbMark )
433 Next
[144]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
[1]450 'マークリストを解放
451 HeapFree(_System_hProcessHeap,0,pbMark)
452
453 If iBackAllSize=iAllSize Then
[144]454 If iAllSize > limitMemorySize Then
455 limitMemorySize = iAllSize
456 End If
457
[1]458 '許容量を拡張する
[144]459 limitMemorySize *= 2
[214]460 limitMemoryObjectNum *= 2
[144]461
462 OutputDebugString( Ex"memory size is extended for gc!\r\n" )
[1]463 End If
464
[144]465 Dim temp[100] As Char
[214]466 wsprintf(temp,Ex"object items ... %d -> %d ( %d MB -> %d MB )\r\n",iBeforeN,n, iBackAllSize\1024\1024, iAllSize\1024\1024)
[144]467 OutputDebugString( temp )
468 wsprintf(temp,Ex"limit size of memory ... %d\r\n",limitMemorySize)
469 OutputDebugString( temp )
[214]470 wsprintf(temp,Ex"garbage colletion sweep finish! (%d ms)\r\n\r\n", GetTickCount()-startTime)
471 OutputDebugString( temp )
[1]472
[144]473
[1]474 '-------------------------------------
475 ' すべてのスレッドを再開
476 '-------------------------------------
[18]477 _System_pobj_AllThreads->ResumeAllThread()
[171]478
479 LeaveCriticalSection(CriticalSection)
[1]480 End Function
481
[144]482 ' 未解放のメモリオブジェクトをトレース
483 Sub DumpMemoryLeaks()
484 Dim isLeak = False
[1]485 Dim i As Long
486 For i=0 To ELM(n)
[144]487 If ppPtr[i] Then
488 If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 Then
489 If isLeak = False Then
490 OutputDebugString( Ex"Detected memory leaks!\r\n" )
491 isLeak = True
492 End If
[1]493
[144]494 Dim temp[100] As Char
495 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 OutputDebugString( temp )
[1]498 End If
499 End If
500 Next
[144]501
502 If isLeak Then
503 OutputDebugString( Ex"Object dump complete.\r\n" )
504 End If
[170]505
[1]506 End Sub
[144]507
[1]508End Class
509
510'GC管理用の特殊なシステムオブジェクト(デストラクタは最終のタイミングで呼び出されます)
[144]511Dim _System_pGC As *_System_CGarbageCollection
[1]512
513
514
515Function GC_malloc(size As Long) As VoidPtr
516 ' sweep
[144]517 _System_pGC->sweep()
[1]518
519 'allocate
[144]520 Return _System_pGC->__malloc(size,0)
[1]521End Function
522
523Function GC_malloc_atomic(size As Long) As VoidPtr
524 ' sweep
[144]525 _System_pGC->sweep()
[1]526
527 'allocate
[144]528 Return _System_pGC->__malloc(size,_System_GC_FLAG_ATOMIC)
[1]529End Function
[144]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.