source: trunk/ab5.0/ablib/src/system/gc.sbp @ 560

Last change on this file since 560 was 546, checked in by dai, 15 years ago

VarPtr?(This)をエラーとして扱うようにした。
・デリゲート生成時にThisに対するオブジェクトポインタが正常に取得できないバグを修正。
(※64bit版を後日対応すること)

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