source: trunk/Include/system/gc.sbp@ 399

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

alloc, reallocに失敗したとき、例外を投げるようにした

File size: 21.6 KB
RevLine 
[360]1/*!
2 @brief このファイルでは、ABのガベージコレクションの実装を行います。
[109]3*/
[1]4
[109]5
[1]6/*
7※これらの変数はコンパイラが自動的に定義します。
8Dim _System_gc_StackRoot_StartPtr As VoidPtr
9*/
10
11Const _System_GC_FLAG_ATOMIC = 1
12Const _System_GC_FLAG_NEEDFREE = 2
13Const _System_GC_FLAG_INITZERO = 4
[144]14Const _System_GC_FLAG_OBJECT = 8
[1]15
[214]16Type _System_GlobalRoot
17 ptr As *LONG_PTR
18 count As Long
19End Type
20
[361]21Type _System_MemoryObject
22 ptr As VoidPtr
[370]23 size As SIZE_T
[361]24 flags As DWord
25 generationCount As Long
26End Type
27
[1]28Class _System_CGarbageCollection
[266]29
[369]30 hHeap As HANDLE ' GC用のヒープ
31
[361]32 pMemoryObjects As *_System_MemoryObject ' メモリオブジェクト
33 countOfMemoryObjects As Long ' 管理するメモリオブジェクトの個数
[1]34
35 iAllSize As SIZE_T
36
[360]37 isSweeping As Boolean ' スウィープ中かどうか
[144]38
[369]39 minPtr As ULONG_PTR
40 maxPtr As ULONG_PTR
41
[360]42 ' クリティカルセクション
[1]43 CriticalSection As CRITICAL_SECTION
44
[214]45 ' メモリの上限値(この値を超えるとGCが発動します)
46 limitMemorySize As LONG_PTR ' バイト単位
47 limitMemoryObjectNum As Long ' メモリオブジェクトの個数単位
[109]48
[360]49 isFinish As Boolean ' GC管理が終了したかどうか
[144]50
51
[214]52 ' Global Root
53 pGlobalRoots As *_System_GlobalRoot
54 globalRootNum As Long
55 Sub AddGlobalRootPtr( ptr As *LONG_PTR, count As Long )
56 pGlobalRoots = _System_realloc( pGlobalRoots, (globalRootNum + 1) * SizeOf(_System_GlobalRoot) )
57 pGlobalRoots[globalRootNum].ptr = ptr
58 pGlobalRoots[globalRootNum].count = count
59 globalRootNum++
60 End Sub
61
62 Sub RegisterGlobalRoots()
63 ' このメソッドの実装はコンパイラが自動生成する
64
65 ' AddGlobalRootPtr(...)
66 ' ...
67 End Sub
68
[144]69 ' 特殊クラスのため、コンストラクタ・デストラクタは呼ばれません
[1]70 Sub _System_CGarbageCollection()
[144]71 End Sub
72 Sub ~_System_CGarbageCollection()
73 End Sub
74
[214]75Public
76
[360]77 /*!
78 @brief 環境変数にGCを登録する
79 @author Daisuke Yamamoto
80 @date 2007/10/21
81 */
[266]82 Static Sub Initialize()
83 Dim temporary[255] As Char
84 If GetEnvironmentVariable( "ActiveBasicGarbageCollection", temporary, 255 ) Then
85 ' 既にGCがプロセスに存在するとき
[364]86 _stscanf( temporary, "%08x", VarPtr( _System_pGC ) )
[266]87 MessageBox(0,temporary,"GetEnvironmentVariable",0)
88 Else
89 _System_pGC = _System_calloc( SizeOf( _System_CGarbageCollection ) )
90 _System_pGC->Begin()
91
92 ' GCをプロセスに登録する
[364]93 _stprintf( temporary, "%08x", _System_pGC )
[266]94 SetEnvironmentVariable( "ActiveBasicGarbageCollection", temporary )
95 End If
96 End Sub
97
[360]98 /*!
99 @brief メモリサイズの上限を指定する
100 @param limitMemorySize メモリサイズの上限(単位はバイト)
101 limitMemoryObjectNum メモリ個数の上限
102 @author Daisuke Yamamoto
103 @date 2007/10/21
104 */
105 Sub SetLimit( limitMemorySize As LONG_PTR, limitMemoryObjectNum As Long )
106 This.limitMemorySize = limitMemorySize
107 This.limitMemoryObjectNum = limitMemoryObjectNum
108 End Sub
109
110 /*!
111 @brief 初期化
112 @author Daisuke Yamamoto
113 @date 2007/10/21
114 */
[144]115 Sub Begin()
[361]116 If pMemoryObjects Then Exit Sub
[1]117
[144]118 isFinish = False
119
120 'メモリの上限値(この値を超えるとGCが発動します)
[362]121 SetLimit(
122 1024*1024, ' バイト単位
123 2000 ' メモリオブジェクトの個数単位
124 )
[144]125
[369]126 hHeap = HeapCreate( 0, 0, 0 )
127
[361]128 pMemoryObjects = _System_calloc( 1 )
129 countOfMemoryObjects=0
[1]130
[214]131 ' Global Root
132 pGlobalRoots = _System_calloc( 1 )
133 globalRootNum = 0
134 RegisterGlobalRoots()
135
[1]136 iAllSize=0
137
[144]138 ' スウィープ中かどうか
139 isSweeping = False
[1]140
[369]141 minPtr = &HFFFFFFFFFFFFFFFF As ULONG_PTR
142 maxPtr = 0
143
[1]144 'クリティカルセッションを生成
145 InitializeCriticalSection(CriticalSection)
146
[18]147
148 '---------------------------
149 ' 開始時のスレッドを通知
150 '---------------------------
[1]151 Dim hTargetThread As HANDLE
152 DuplicateHandle(GetCurrentProcess(),
153 GetCurrentThread(),
154 GetCurrentProcess(),
155 hTargetThread, 0, FALSE, DUPLICATE_SAME_ACCESS) 'カレントスレッドのハンドルを複製
[18]156
[144]157 ' スレッド管理用オブジェクトを生成
158 _System_pobj_AllThreads = New _System_CThreadCollection()
[18]159
[144]160 ' 自身のThreadオブジェクトを生成
161 Dim thread As Thread(hTargetThread,GetCurrentThreadId(),0)
[330]162 thread.Name = "main"
[18]163
[232]164 _System_pobj_AllThreads->BeginThread(ObjPtr( thread ),_System_gc_StackRoot_StartPtr As *LONG_PTR)
[144]165
[1]166 End Sub
[360]167
168 /*!
169 @brief 終了処理
170 @author Daisuke Yamamoto
171 @date 2007/10/21
172 */
[144]173 Sub Finish()
[361]174 If pMemoryObjects = NULL Then Exit Sub
[1]175
[144]176 isFinish = True
[79]177
[144]178 ' スレッド管理用オブジェクトを破棄
179 Delete _System_pobj_AllThreads
[1]180
[144]181 ' 自分以外のスレッドを一時停止
182 '_System_pobj_AllThreads->SuspendAnotherThread()
183
[259]184 _System_DebugOnly_OutputDebugString( Ex"garbage colletion sweeping all memory objects!\r\n" )
[144]185 DeleteAllGarbageMemories()
186
187 ' 未解放のメモリオブジェクトをトレース
188 DumpMemoryLeaks()
189
190 ' 自分以外のスレッドを再開
191 '_System_pobj_AllThreads->ResumeAnotherThread()
192
[361]193 _System_free( pMemoryObjects )
194 pMemoryObjects = NULL
[1]195
[214]196 _System_free( pGlobalRoots )
197 pGlobalRoots = NULL
198
[1]199 'クリティカルセッションを破棄
200 DeleteCriticalSection(CriticalSection)
[144]201
[79]202 End Sub
[1]203
[360]204 /*!
[361]205 @brief メモリオブジェクトからインデックスを取得する
206 @param new_ptr メモリオブジェクトへのポインタ
207 @author Daisuke Yamamoto
208 @date 2007/10/21
209 */
210 Function GetMemoryObjectPtr( ptr As VoidPtr ) As *_System_MemoryObject
211 ' メモリオブジェクトの先頭部分からインデックスを取得する
212 Dim index = Get_LONG_PTR( ptr - SizeOf(LONG_PTR) ) As Long
213
214 If pMemoryObjects[index].ptr <> ptr Then
215 ' メモリイメージが壊れている(先頭に存在するインデックスの整合性が取れない)
216 Dim temporary[1024] As Char
[364]217#ifdef _WIN64
218 'wsprintfでは、Windows 2000以降でしか%pが使えない。
219 wsprintf( temporary, Ex"indexOfMemoryObjects: %d\r\npMemoryObjects[index].ptr: &H%p\r\nptr: &H%p\r\n",
220 index,
221 pMemoryObjects[index].ptr,
222 ptr )
223#else
[361]224 wsprintf( temporary, Ex"indexOfMemoryObjects: %d\r\npMemoryObjects[index].ptr: &H%08x\r\nptr: &H%08x\r\n",
225 index,
226 pMemoryObjects[index].ptr,
227 ptr )
[364]228#endif
[361]229 _System_DebugOnly_OutputDebugString( temporary )
230 debug
231 End If
232
233 Return VarPtr( pMemoryObjects[index] )
234 End Function
235
236 /*!
[360]237 @brief メモリオブジェクトを追加する
238 @param new_ptr メモリオブジェクトへのポインタ
239 size メモリオブジェクトのサイズ
240 flags メモリオブジェクトの属性
241 @author Daisuke Yamamoto
242 @date 2007/10/21
243 */
[170]244 Sub add(new_ptr As VoidPtr, size As SIZE_T, flags As DWord)
[144]245 EnterCriticalSection(CriticalSection)
[361]246 iAllSize+=size
[1]247
[361]248 ' メモリオブジェクトインスタンスの先頭にインデックスをセットする
249 Set_LONG_PTR( new_ptr - SizeOf( LONG_PTR ), countOfMemoryObjects )
[1]250
[361]251 pMemoryObjects = _System_realloc( pMemoryObjects, (countOfMemoryObjects+1)*SizeOf(_System_MemoryObject) )
252 pMemoryObjects[countOfMemoryObjects].ptr = new_ptr
253 pMemoryObjects[countOfMemoryObjects].size = size
254 pMemoryObjects[countOfMemoryObjects].flags = flags
255 pMemoryObjects[countOfMemoryObjects].generationCount = 0
[360]256
[369]257 If minPtr > new_ptr As ULONG_PTR Then
258 minPtr = new_ptr As ULONG_PTR
259 End If
260 If maxPtr < ( new_ptr + size ) As ULONG_PTR Then
261 maxPtr = ( new_ptr + size ) As ULONG_PTR
262 End If
263
[361]264 countOfMemoryObjects++
[144]265 LeaveCriticalSection(CriticalSection)
[1]266
[330]267 /*
268 ' デバッグ用
[361]269 If countOfMemoryObjects = 1996 Then
[330]270 debug
271 End If
272 */
[1]273 End Sub
274
275
[360]276 /*!
277 @brief メモリオブジェクトを確保する
278 @param size メモリオブジェクトのサイズ
279 flags メモリオブジェクトの属性
280 @author Daisuke Yamamoto
281 @date 2007/10/21
282 */
[1]283 Function __malloc(size As SIZE_T,flags As Byte) As VoidPtr
[361]284 Dim dwFlags As DWord
285 If flags and _System_GC_FLAG_INITZERO Then
286 dwFlags=HEAP_ZERO_MEMORY
287 Else
288 dwFlags=0
289 End If
[1]290
[361]291 ' 実際のメモリバッファはインデックスの分だけ多めに確保する
[399]292 __malloc = HeapAlloc( hHeap, dwFlags, size + SizeOf( LONG_PTR ) )
293 throwIfAllocationFailed( __malloc, size )
294 __malloc += SizeOf( LONG_PTR )
[1]295
[361]296 ' 管理対象のメモリオブジェクトとして追加
[399]297 add( __malloc, size, flags )
[1]298 End Function
299
[360]300 /*!
301 @brief メモリオブジェクトを再確保する
302 @param lpMem メモリオブジェクトへのポインタ
303 size メモリオブジェクトのサイズ
304 flags メモリオブジェクトの属性
305 @author Daisuke Yamamoto
306 @date 2007/10/21
307 */
[1]308 Function __realloc(lpMem As VoidPtr, size As SIZE_T) As VoidPtr
[18]309 EnterCriticalSection(CriticalSection)
[1]310
[361]311 ' メモリオブジェクトを取得
312 Dim pTempMemoryObject = GetMemoryObjectPtr( lpMem )
[18]313
[361]314 iAllSize += size - pTempMemoryObject->size
315
316 pTempMemoryObject->size = size
[399]317 __realloc = HeapReAlloc( hHeap, HEAP_ZERO_MEMORY, pTempMemoryObject->ptr - SizeOf(LONG_PTR), size + SizeOf(LONG_PTR) )
318 If __realloc = 0 Then
319 LeaveCriticalSection(CriticalSection)
320 throwIfAllocationFailed(0, size)
321 End If
322 __realloc += SizeOf(LONG_PTR)
323 pTempMemoryObject->ptr = __realloc
[361]324
[399]325
[369]326 If minPtr > pTempMemoryObject->ptr As ULONG_PTR Then
327 minPtr = pTempMemoryObject->ptr As ULONG_PTR
328 End If
329 If maxPtr < ( pTempMemoryObject->ptr + size ) As ULONG_PTR Then
330 maxPtr = ( pTempMemoryObject->ptr + size ) As ULONG_PTR
331 End If
[18]332 LeaveCriticalSection(CriticalSection)
[1]333 End Function
334
[360]335 /*!
[399]336 @brief メモリ確保に失敗したか(NULLかどうか)を調べ、失敗していたら例外を投げる。
337 @param[in] p メモリへのポインタ
338 @param[in] size 確保しようとした大きさ
339 @exception OutOfMemoryException pがNULLだったとき
340 @author Egtra
341 @date 2007/12/24
342 ただし、sizeがあまりにも小さい場合は、例外を投げず、即座に終了する。
343 */
344 Sub throwIfAllocationFailed(p As VoidPtr, size As SIZE_T)
345 If p = 0 Then
346 If size < 256 Then
347 /*
348  これだけのメモリも確保できない状況では、OutOfMemoryException
349 のインスタンスすら作成できないかもしれないし、例え作成できても、
350 その後、結局メモリ不足でろくなことを行えないはず。そのため、
351 ここですぐに終了することにする。
352  なお、この値は特に根拠があって定められた値ではない。
353 */
354 HeapDestroy(hHeap)
355 OutputDebugString("AB malloc: Out of memory.")
356 ExitProcess(-1)
357 End If
358 Throw New System.OutOfMemoryException(ActiveBasic.Strings.SPrintf("malloc: Failed to allocate %zu byte(s) memory.", New System.UInt64(size)))
359 End If
360 End Sub
361
362 /*!
[360]363 @brief メモリオブジェクトを解放する
364 @param lpMem メモリオブジェクトへのポインタ
365 isSweeping スウィープ中にこのメソッドが呼ばれるときはTrue、それ以外はFalse
366 @author Daisuke Yamamoto
367 @date 2007/10/21
368 */
[144]369 Sub __free_ex(lpMem As VoidPtr, isSweeping As Boolean)
[18]370 EnterCriticalSection(CriticalSection)
[1]371
[361]372 ' メモリオブジェクトを取得
373 Dim pTempMemoryObject = GetMemoryObjectPtr( lpMem )
374
375 If (pTempMemoryObject->flags and _System_GC_FLAG_NEEDFREE)<>0 or isSweeping Then
376 iAllSize -= pTempMemoryObject->size
377
[369]378 HeapFree( hHeap, 0, pTempMemoryObject->ptr - SizeOf(LONG_PTR) )
[361]379 pTempMemoryObject->ptr = NULL
380 pTempMemoryObject->size = 0
381 Else
382 If isFinish = False Then
383 _System_DebugOnly_OutputDebugString( Ex"heap free missing!\r\n" )
[1]384 End If
[361]385 End If
[18]386 LeaveCriticalSection(CriticalSection)
[1]387 End Sub
388
[360]389 /*!
390 @brief メモリオブジェクトを解放する
391 @param lpMem メモリオブジェクトへのポインタ
392 @author Daisuke Yamamoto
393 @date 2007/10/21
394 */
[144]395 Sub __free(lpMem As VoidPtr)
396 __free_ex( lpMem, False )
397 End Sub
398
[360]399 /*!
[368]400 @brief 必要であればスウィープする
[360]401 @author Daisuke Yamamoto
402 @date 2007/10/21
403 */
[368]404 Sub TrySweep()
[361]405 If isSweeping <> False or (iAllSize<limitMemorySize and countOfMemoryObjects<limitMemoryObjectNum) Then
[171]406 'メモリ使用量が上限値を超えていないとき
407 Exit Sub
408 End If
[144]409
[368]410 Sweep()
411 End Sub
412
413 /*!
414 @brief スウィープする
415 @author Daisuke Yamamoto
416 @date 2007/10/21
417 */
418 Sub Sweep()
[171]419 Dim hThread As HANDLE
420 Dim ThreadId As DWord
421 hThread=_beginthreadex(NULL,0,AddressOf(SweepOnOtherThread),VarPtr(This),0,ThreadId)
422 WaitForSingleObject(hThread,INFINITE)
423 CloseHandle(hThread)
[202]424 isSweeping = False
[1]425 End Sub
426
[144]427Private
[1]428
[214]429 Static Function IsNull( object As Object ) As Boolean
[237]430 Return Object.ReferenceEquals(object, Nothing)
[214]431 End Function
432
[360]433 /*!
434 @brief メモリオブジェクトの生存検地
435 @param pSample メモリオブジェクトへのポインタ
436 @author Daisuke Yamamoto
437 @date 2007/10/21
438 */
[144]439 Function HitTest(pSample As VoidPtr) As Long
[368]440 If pSample = NULL Then
441 Return -1
442 End If
[369]443 If not( minPtr <= pSample and pSample <= maxPtr ) Then
444 Return -1
445 End If
[368]446
[144]447 Dim i As Long
[361]448 For i=0 To ELM(countOfMemoryObjects)
449 If (pMemoryObjects[i].ptr As LONG_PTR)<=(pSample As LONG_PTR) and (pSample As LONG_PTR)<((pMemoryObjects[i].ptr As LONG_PTR)+pMemoryObjects[i].size) Then
[144]450 Return i
451 End If
452 Next
453 Return -1
454 End Function
[1]455
[360]456 /*!
457 @brief オブジェクトのスキャン
458 @param pObject オブジェクトへのポインタ
459 pbMark マークリスト
460 @author Daisuke Yamamoto
461 @date 2007/10/21
462 */
[214]463 Function ScanObject(pObject As *Object, pbMark As *Byte) As Boolean
[275]464 Dim classTypeInfo = Nothing As ActiveBasic.Core._System_TypeForClass
465 classTypeInfo = pObject->GetType() As ActiveBasic.Core._System_TypeForClass
[214]466
467 If IsNull( classTypeInfo ) Then
468 Return False
469 End If
470
[330]471 /*
472 _System_DebugOnly_OutputDebugString( " (scanning object)" )
473 _System_DebugOnly_OutputDebugString( classTypeInfo.Name )
474 _System_DebugOnly_OutputDebugString( Ex"\r\n" )
475 */
476
[214]477 Dim i As Long
478 For i = 0 To ELM(classTypeInfo.numOfReference)
479 Scan( (pObject + classTypeInfo.referenceOffsets[i]) As *LONG_PTR, 1, pbMark )
480 Next
481
482 Return True
483 End Function
484
[360]485 /*!
486 @brief メモリオブジェクトのスキャン
487 @param pStartPtr メモリオブジェクトへのポインタ
488 maxNum スキャンするメモリオブジェクトの個数
489 pbMark マークリスト
490 @author Daisuke Yamamoto
491 @date 2007/10/21
492 */
[214]493 Sub Scan(pStartPtr As *LONG_PTR, maxNum As Long, pbMark As *Byte)
494 Dim i As Long, index As Long
495
496 For i=0 To ELM(maxNum)
[144]497 index=HitTest(pStartPtr[i] As VoidPtr)
498 If index<>-1 Then
499 If pbMark[index]=0 Then
500 pbMark[index]=1
[170]501
[361]502 ' ジェネレーションカウントを増やす
503 pMemoryObjects[index].generationCount ++
504
505 If pMemoryObjects[index].flags and _System_GC_FLAG_OBJECT Then
[214]506 ' オブジェクトの場合
[361]507 If ScanObject( (pMemoryObjects[index].ptr + 4*SizeOf(LONG_PTR)) As *Object, pbMark) = False Then
508 Dim maxNum = (pMemoryObjects[index].size\SizeOf(LONG_PTR)) As Long
509 Scan(pMemoryObjects[index].ptr As *LONG_PTR, maxNum, pbMark)
[214]510 End If
511
[361]512 ElseIf (pMemoryObjects[index].flags and _System_GC_FLAG_ATOMIC)=0 Then
[214]513 ' ヒープ領域がポインタ値を含む可能性があるとき
[361]514 If pMemoryObjects[index].ptr = NULL Then
[144]515 'エラー
[170]516
[144]517 End If
[214]518
[361]519 Dim maxNum = (pMemoryObjects[index].size\SizeOf(LONG_PTR)) As Long
520 Scan(pMemoryObjects[index].ptr As *LONG_PTR, maxNum, pbMark)
[144]521 End If
522 End If
523 End If
524 Next
525 End Sub
[1]526
[360]527 /*!
528 @brief グローバル領域をルートに指定してスキャン
529 @param pbMark マークリスト
530 @author Daisuke Yamamoto
531 @date 2007/10/21
532 */
533 Sub GlobalScan( pbMark As *Byte )
534 Dim i As Long
535 For i = 0 To ELM( globalRootNum )
536 Scan( pGlobalRoots[i].ptr, pGlobalRoots[i].count, pbMark )
537 Next
538 End Sub
539
540 /*!
541 @brief ローカル領域をルートに指定してスキャン
542 @param pbMark マークリスト
543 @author Daisuke Yamamoto
544 @date 2007/10/21
545 */
[144]546 Sub LocalScan( pbMark As *Byte )
[18]547 Dim Context As CONTEXT
[1]548 Dim NowSp As *LONG_PTR
549 Dim size As LONG_PTR
[18]550 Dim i As Long
551 For i=0 To ELM(_System_pobj_AllThreads->ThreadNum)
[330]552 Dim thread = _System_pobj_AllThreads->ppobj_Thread[i]
553 If thread Then
[1]554 FillMemory(VarPtr(Context),SizeOf(CONTEXT),0)
555 Context.ContextFlags=CONTEXT_CONTROL
[330]556 If thread->__GetContext(Context)=0 Then
[259]557 _System_DebugOnly_OutputDebugString(Ex"レジスタ情報の取得に失敗しました。\r\n")
[1]558 End If
559
560#ifdef _WIN64
561 NowSp=Context.Rsp As *LONG_PTR
562#else
563 NowSp=Context.Esp As *LONG_PTR
564#endif
565
[214]566 Dim size=(_System_pobj_AllThreads->pStackBase[i] As LONG_PTR)-(NowSp As LONG_PTR)
567 Dim maxNum = (size\SizeOf(LONG_PTR)) As Long
[1]568
[144]569 If NowSp = 0 Then
570 debug
571 Exit Sub
572 End If
573
[330]574 /*
575 _System_DebugOnly_OutputDebugString( "(scanning thread local)" )
576 _System_DebugOnly_OutputDebugString( thread.Name )
577 _System_DebugOnly_OutputDebugString( Ex"\r\n" )
578 */
579
[214]580 Scan( NowSp, maxNum, pbMark )
[1]581 End If
582 Next
[144]583 End Sub
[1]584
[360]585 /*!
586 @brief 生存していないメモリオブジェクトを解放する
587 @param pbMark マークリスト
588 @author Daisuke Yamamoto
589 @date 2007/10/21
590 */
[144]591 Sub DeleteGarbageMemories( pbMark As *Byte )
[1]592
[144]593 Dim isAllDelete = False
594 If pbMark = NULL Then
595 ' すべてを破棄するとき
596 isAllDelete = True
[361]597 pbMark = _System_calloc( countOfMemoryObjects )
[144]598 End If
[1]599
[144]600 Dim i As Long
[361]601 For i=0 To ELM(countOfMemoryObjects)
602 If pbMark[i]=0 and pMemoryObjects[i].ptr<>0 and (pMemoryObjects[i].flags and _System_GC_FLAG_NEEDFREE)=0 Then
603 If pMemoryObjects[i].ptr = NULL Then
[144]604 If isAllDelete Then
605 Continue
606 Else
607 debug
608 End If
609 End If
[1]610
[361]611 Dim ptr = pMemoryObjects[i].ptr
612 Dim size = pMemoryObjects[i].size
[144]613
[361]614 If (pMemoryObjects[i].flags and _System_GC_FLAG_OBJECT) <> 0 Then
[144]615 /* ・オブジェクトの個数
616 ・オブジェクトのサイズ
617 ・デストラクタの関数ポインタ
[249]618 ・リザーブ領域
[144]619 を考慮 */
[249]620 _System_SweepingDelete (ptr + SizeOf( LONG_PTR ) * 4 )
[144]621 Else
[361]622 __free_ex( ptr, True )
[144]623 End If
[1]624 End If
625 Next
626
[144]627 If isAllDelete Then
628 _System_free( pbMark )
629 End If
630
631 End Sub
632
[360]633 /*!
634 @brief GCが管理するすべてのメモリオブジェクトを解放する
635 @author Daisuke Yamamoto
636 @date 2007/10/21
637 */
[144]638 Sub DeleteAllGarbageMemories()
639 DeleteGarbageMemories( NULL )
640 End Sub
641
[360]642 /*!
643 @brief コンパクション
644 @author Daisuke Yamamoto
645 @date 2007/10/21
646 */
[144]647 Sub Compaction()
648 Dim i As Long, i2 = 0 As Long
[361]649 For i=0 To ELM(countOfMemoryObjects)
650 pMemoryObjects[i2] = pMemoryObjects[i]
[144]651
[361]652 If pMemoryObjects[i2].ptr Then
653 ' メモリオブジェクトの先頭部分にあるインデックスを書き換える
654 Set_LONG_PTR( pMemoryObjects[i2].ptr - SizeOf(LONG_PTR), i2 )
655
[144]656 i2++
657 End If
658 Next
[361]659 countOfMemoryObjects = i2
[144]660 End Sub
661
[360]662 /*!
663 @brief スウィープ(新規スレッドで呼び出す必要あり)
664 @author Daisuke Yamamoto
665 @date 2007/10/21
666 */
[284]667 Function SweepOnOtherThread() As Long
[171]668 EnterCriticalSection(CriticalSection)
[144]669
[214]670
671 Dim startTime = GetTickCount()
672
[259]673 _System_DebugOnly_OutputDebugString( Ex"garbage colletion sweep start!\r\n" )
[214]674
675
[368]676 'If isSweeping <> False or (iAllSize<limitMemorySize and countOfMemoryObjects<limitMemoryObjectNum) Then
677 ' ExitThread(0)
678 'End If
[203]679 isSweeping = True
[202]680
[144]681 ' すべてのスレッドを一時停止
682 _System_pobj_AllThreads->SuspendAllThread()
683
684 ' マークリストを生成
[369]685 Dim pbMark = _System_calloc(countOfMemoryObjects*SizeOf(Byte)) As *Byte
[144]686
687 ' グローバル領域をルートに指定してスキャン
[360]688 GlobalScan( pbMark )
[144]689
690 ' ローカル領域をルートに指定してスキャン
691 LocalScan( pbMark )
692
693 ' スウィープ前のメモリサイズを退避
694 Dim iBackAllSize = iAllSize
695
696 ' スウィープ前のメモリオブジェクトの数
[361]697 Dim iBeforeN = countOfMemoryObjects
[144]698
699 '使われていないメモリを解放する
700 DeleteGarbageMemories(pbMark)
701
702 'コンパクション
703 Compaction()
704
[1]705 'マークリストを解放
[369]706 _System_free(pbMark)
[1]707
[299]708 If iBackAllSize <= iAllSize * 2 Then
[144]709 If iAllSize > limitMemorySize Then
710 limitMemorySize = iAllSize
711 End If
712
[1]713 '許容量を拡張する
[144]714 limitMemorySize *= 2
[214]715 limitMemoryObjectNum *= 2
[144]716
[259]717 _System_DebugOnly_OutputDebugString( Ex"memory size is extended for gc!\r\n" )
[1]718 End If
719
[144]720 Dim temp[100] As Char
[361]721 wsprintf(temp,Ex"object items ... %d -> %d ( %d MB -> %d MB )\r\n",iBeforeN,countOfMemoryObjects, iBackAllSize\1024\1024, iAllSize\1024\1024)
[259]722 _System_DebugOnly_OutputDebugString( temp )
[144]723 wsprintf(temp,Ex"limit size of memory ... %d\r\n",limitMemorySize)
[259]724 _System_DebugOnly_OutputDebugString( temp )
[214]725 wsprintf(temp,Ex"garbage colletion sweep finish! (%d ms)\r\n\r\n", GetTickCount()-startTime)
[259]726 _System_DebugOnly_OutputDebugString( temp )
[1]727
[144]728
[1]729 '-------------------------------------
730 ' すべてのスレッドを再開
731 '-------------------------------------
[18]732 _System_pobj_AllThreads->ResumeAllThread()
[171]733
734 LeaveCriticalSection(CriticalSection)
[1]735 End Function
736
[360]737 /*!
738 @brief 未解放のメモリオブジェクトをデバッグ出力する
739 @author Daisuke Yamamoto
740 @date 2007/10/21
741 */
[144]742 Sub DumpMemoryLeaks()
743 Dim isLeak = False
[1]744 Dim i As Long
[361]745 For i=0 To ELM(countOfMemoryObjects)
746 If pMemoryObjects[i].ptr Then
747 If (pMemoryObjects[i].flags and _System_GC_FLAG_NEEDFREE)<>0 Then
[144]748 If isLeak = False Then
[259]749 _System_DebugOnly_OutputDebugString( Ex"Detected memory leaks!\r\n" )
[144]750 isLeak = True
751 End If
[1]752
[144]753 Dim temp[100] As Char
[259]754 _System_DebugOnly_OutputDebugString( Ex"heap free missing!\r\n" )
[364]755#ifdef _WIN64
756 wsprintf(temp,Ex"{%d} normal block at &H%p, %d bytes long.\r\n", i, pMemoryObjects[i].ptr, pMemoryObjects[i].size)
757#else
[361]758 wsprintf(temp,Ex"{%d} normal block at &H%08X, %d bytes long.\r\n", i, pMemoryObjects[i].ptr, pMemoryObjects[i].size)
[364]759#endif
[259]760 _System_DebugOnly_OutputDebugString( temp )
[1]761 End If
762 End If
763 Next
[144]764
765 If isLeak Then
[259]766 _System_DebugOnly_OutputDebugString( Ex"Object dump complete.\r\n" )
[144]767 End If
[170]768
[1]769 End Sub
[144]770
[1]771End Class
772
773'GC管理用の特殊なシステムオブジェクト(デストラクタは最終のタイミングで呼び出されます)
[144]774Dim _System_pGC As *_System_CGarbageCollection
[1]775
776
777
778Function GC_malloc(size As Long) As VoidPtr
779 ' sweep
[368]780 _System_pGC->TrySweep()
[1]781
782 'allocate
[144]783 Return _System_pGC->__malloc(size,0)
[1]784End Function
785
786Function GC_malloc_atomic(size As Long) As VoidPtr
787 ' sweep
[368]788 _System_pGC->TrySweep()
[1]789
790 'allocate
[144]791 Return _System_pGC->__malloc(size,_System_GC_FLAG_ATOMIC)
[1]792End Function
[144]793
794Function _System_GC_malloc_ForObject(size As Long) As VoidPtr
795 ' sweep
[368]796 _System_pGC->TrySweep()
[144]797
798 'allocate
799 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO)
800End Function
801
802Function _System_GC_malloc_ForObjectPtr(size As Long) As VoidPtr
803 ' sweep
[368]804 _System_pGC->TrySweep()
[144]805
806 'allocate
807 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO or _System_GC_FLAG_NEEDFREE)
808End Function
809
810Function _System_GC_free_for_SweepingDelete( ptr As *Object )
811 ' free
812 _System_pGC->__free_ex( ptr, True )
813End Function
Note: See TracBrowser for help on using the repository browser.