source: branch/egtra-gdiplus/system/gc.sbp@ 353

Last change on this file since 353 was 237, checked in by イグトランス (egtra), 18 years ago

#_fullcompileで検出されたエラーの修正(明らかに判るもののみ)

File size: 13.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
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 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 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] + 3*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 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 _System_SweepingDelete (ptr + SizeOf( LONG_PTR ) * 3 )
375 Else
376 HeapFree(_System_hProcessHeap,0,ptr)
377 End If
378
379 iAllSize-=size
380 End If
381 Next
382
383 If isAllDelete Then
384 _System_free( pbMark )
385 End If
386
387 End Sub
388
389 Sub DeleteAllGarbageMemories()
390 DeleteGarbageMemories( NULL )
391 End Sub
392
393 Sub Compaction()
394 Dim i As Long, i2 = 0 As Long
395 For i=0 To ELM(n)
396 ppPtr[i2] = ppPtr[i]
397 pSize[i2] = pSize[i]
398 pdwFlags[i2] = pdwFlags[i]
399
400 If ppPtr[i] Then
401 i2++
402 End If
403 Next
404 n = i2
405 End Sub
406
407 ' スウィープ(新規スレッドで呼び出し)
408 Function Cdecl SweepOnOtherThread() As Long
409 EnterCriticalSection(CriticalSection)
410
411
412 Dim startTime = GetTickCount()
413
414 OutputDebugString( Ex"garbage colletion sweep start!\r\n" )
415
416
417 If isSweeping <> False or (iAllSize<limitMemorySize and n<limitMemoryObjectNum) Then
418 ExitThread(0)
419 End If
420 isSweeping = True
421
422 ' すべてのスレッドを一時停止
423 _System_pobj_AllThreads->SuspendAllThread()
424
425 ' マークリストを生成
426 Dim pbMark = HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,n*SizeOf(Byte)) As *Byte
427
428 ' グローバル領域をルートに指定してスキャン
429 Dim i As Long
430 For i = 0 To ELM( globalRootNum )
431 Scan( pGlobalRoots[i].ptr, pGlobalRoots[i].count, pbMark )
432 Next
433
434 ' ローカル領域をルートに指定してスキャン
435 LocalScan( pbMark )
436
437 ' スウィープ前のメモリサイズを退避
438 Dim iBackAllSize = iAllSize
439
440 ' スウィープ前のメモリオブジェクトの数
441 Dim iBeforeN = n
442
443 '使われていないメモリを解放する
444 DeleteGarbageMemories(pbMark)
445
446 'コンパクション
447 Compaction()
448
449 'マークリストを解放
450 HeapFree(_System_hProcessHeap,0,pbMark)
451
452 If iBackAllSize=iAllSize Then
453 If iAllSize > limitMemorySize Then
454 limitMemorySize = iAllSize
455 End If
456
457 '許容量を拡張する
458 limitMemorySize *= 2
459 limitMemoryObjectNum *= 2
460
461 OutputDebugString( Ex"memory size is extended for gc!\r\n" )
462 End If
463
464 Dim temp[100] As Char
465 wsprintf(temp,Ex"object items ... %d -> %d ( %d MB -> %d MB )\r\n",iBeforeN,n, iBackAllSize\1024\1024, iAllSize\1024\1024)
466 OutputDebugString( temp )
467 wsprintf(temp,Ex"limit size of memory ... %d\r\n",limitMemorySize)
468 OutputDebugString( temp )
469 wsprintf(temp,Ex"garbage colletion sweep finish! (%d ms)\r\n\r\n", GetTickCount()-startTime)
470 OutputDebugString( temp )
471
472
473 '-------------------------------------
474 ' すべてのスレッドを再開
475 '-------------------------------------
476 _System_pobj_AllThreads->ResumeAllThread()
477
478 LeaveCriticalSection(CriticalSection)
479 End Function
480
481 ' 未解放のメモリオブジェクトをトレース
482 Sub DumpMemoryLeaks()
483 Dim isLeak = False
484 Dim i As Long
485 For i=0 To ELM(n)
486 If ppPtr[i] Then
487 If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 Then
488 If isLeak = False Then
489 OutputDebugString( Ex"Detected memory leaks!\r\n" )
490 isLeak = True
491 End If
492
493 Dim temp[100] As Char
494 OutputDebugString( Ex"heap free missing!\r\n" )
495 wsprintf(temp,Ex"{%d} normal block at &H%08X, %d bytes long.\r\n", i, ppPtr[i], pSize[i])
496 OutputDebugString( temp )
497 End If
498 End If
499 Next
500
501 If isLeak Then
502 OutputDebugString( Ex"Object dump complete.\r\n" )
503 End If
504
505 End Sub
506
507End Class
508
509'GC管理用の特殊なシステムオブジェクト(デストラクタは最終のタイミングで呼び出されます)
510Dim _System_pGC As *_System_CGarbageCollection
511
512
513
514Function GC_malloc(size As Long) As VoidPtr
515 ' sweep
516 _System_pGC->sweep()
517
518 'allocate
519 Return _System_pGC->__malloc(size,0)
520End Function
521
522Function GC_malloc_atomic(size As Long) As VoidPtr
523 ' sweep
524 _System_pGC->sweep()
525
526 'allocate
527 Return _System_pGC->__malloc(size,_System_GC_FLAG_ATOMIC)
528End Function
529
530Function _System_GC_malloc_ForObject(size As Long) As VoidPtr
531 ' sweep
532 _System_pGC->sweep()
533
534 'allocate
535 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO)
536End Function
537
538Function _System_GC_malloc_ForObjectPtr(size As Long) As VoidPtr
539 ' sweep
540 _System_pGC->sweep()
541
542 'allocate
543 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO or _System_GC_FLAG_NEEDFREE)
544End Function
545
546Function _System_GC_free_for_SweepingDelete( ptr As *Object )
547 ' free
548 _System_pGC->__free_ex( ptr, True )
549End Function
Note: See TracBrowser for help on using the repository browser.