source: Include/system/gc.sbp @ 170

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

winnt.ab, windef.ab, guiddef.abを導入

File size: 11.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
22Class _System_CGarbageCollection
23    ppPtr As *VoidPtr
24    pSize As *SIZE_T
25    pdwFlags As *DWord
26    n As Long
27
28    iAllSize As SIZE_T
29
30    isSweeping As Boolean
31
32    CriticalSection As CRITICAL_SECTION
33
34    'メモリの上限値(この値を超えるとGCが発動します)
35    '※バイト単位
36    limitMemorySize As LONG_PTR
37
38    isFinish As Boolean
39
40Public
41
42    ' 特殊クラスのため、コンストラクタ・デストラクタは呼ばれません
43    Sub _System_CGarbageCollection()
44    End Sub
45    Sub ~_System_CGarbageCollection()
46    End Sub
47
48    Sub Begin()
49        If ppPtr Then Exit Sub
50
51        isFinish = False
52
53        'メモリの上限値(この値を超えるとGCが発動します)
54        '※バイト単位
55        limitMemorySize = 1024*1024 As LONG_PTR
56
57        ppPtr=_System_calloc( 1 )
58        pSize=_System_calloc( 1 )
59        pdwFlags=_System_calloc( 1 )
60        n=0
61
62        iAllSize=0
63
64        ' スウィープ中かどうか
65        isSweeping = False
66
67        'クリティカルセッションを生成
68        InitializeCriticalSection(CriticalSection)
69
70
71        '---------------------------
72        ' 開始時のスレッドを通知
73        '---------------------------
74        Dim hTargetThread As HANDLE
75        DuplicateHandle(GetCurrentProcess(),
76            GetCurrentThread(),
77            GetCurrentProcess(),
78            hTargetThread, 0, FALSE, DUPLICATE_SAME_ACCESS)     'カレントスレッドのハンドルを複製
79
80        ' スレッド管理用オブジェクトを生成
81        _System_pobj_AllThreads = New _System_CThreadCollection()
82
83        ' 自身のThreadオブジェクトを生成
84        Dim thread As Thread(hTargetThread,GetCurrentThreadId(),0)
85
86        _System_pobj_AllThreads->BeginThread(VarPtr( thread ),_System_gc_StackRoot_StartPtr As *LONG_PTR)
87
88    End Sub
89    Sub Finish()
90        If ppPtr=0 Then Exit Sub
91
92        isFinish = True
93
94        ' スレッド管理用オブジェクトを破棄
95        Delete _System_pobj_AllThreads
96
97        ' 自分以外のスレッドを一時停止
98        '_System_pobj_AllThreads->SuspendAnotherThread()
99
100        OutputDebugString( Ex"garbage colletion sweeping all memory objects!\r\n" )
101        DeleteAllGarbageMemories()
102
103        ' 未解放のメモリオブジェクトをトレース
104        DumpMemoryLeaks()
105
106        ' 自分以外のスレッドを再開
107        '_System_pobj_AllThreads->ResumeAnotherThread()
108
109        HeapFree(_System_hProcessHeap,0,ppPtr)
110        ppPtr=0
111
112        HeapFree(_System_hProcessHeap,0,pSize)
113        pSize=0
114        HeapFree(_System_hProcessHeap,0,pdwFlags)
115        pdwFlags=0
116
117        'クリティカルセッションを破棄
118        DeleteCriticalSection(CriticalSection)
119
120    End Sub
121
122    Sub add(new_ptr As VoidPtr, size As SIZE_T, flags As DWord)
123        iAllSize+=size
124
125        EnterCriticalSection(CriticalSection)
126            ppPtr=HeapReAlloc(_System_hProcessHeap,0,ppPtr,(n+1)*SizeOf(VoidPtr))
127            ppPtr[n]=new_ptr
128
129            pSize=HeapReAlloc(_System_hProcessHeap,0,pSize,(n+1)*SizeOf(SIZE_T))
130            pSize[n]=size
131
132            pdwFlags=HeapReAlloc(_System_hProcessHeap,0,pdwFlags,(n+1)*SizeOf(DWord))
133            pdwFlags[n]=flags
134        LeaveCriticalSection(CriticalSection)
135
136        n++
137    End Sub
138
139
140    Function __malloc(size As SIZE_T,flags As Byte) As VoidPtr
141        EnterCriticalSection(CriticalSection)
142            Dim dwFlags As DWord
143            If flags and _System_GC_FLAG_INITZERO Then
144                dwFlags=HEAP_ZERO_MEMORY
145            Else
146                dwFlags=0
147            End If
148
149            Dim ptr = HeapAlloc(_System_hProcessHeap,dwFlags,size)
150            add( ptr, size, flags )
151        LeaveCriticalSection(CriticalSection)
152
153        Return ptr
154    End Function
155
156    Function __realloc(lpMem As VoidPtr, size As SIZE_T) As VoidPtr
157        EnterCriticalSection(CriticalSection)
158            Dim i As Long
159            For i=0 To ELM(n)
160                If ppPtr[i]=lpMem Then
161                    iAllSize+=size-pSize[i]
162
163                    pSize[i]=size
164                    ppPtr[i]=HeapReAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,lpMem,size)
165
166                    LeaveCriticalSection(CriticalSection)
167                    Return ppPtr[i]
168                End If
169            Next
170        LeaveCriticalSection(CriticalSection)
171        Return 0
172    End Function
173
174    Sub __free_ex(lpMem As VoidPtr, isSweeping As Boolean)
175        EnterCriticalSection(CriticalSection)
176            Dim i As Long
177            For i=0 To ELM(n)
178                If ppPtr[i]=lpMem Then
179                    If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 or isSweeping Then
180                        iAllSize-=pSize[i]
181
182                        HeapFree(_System_hProcessHeap,0,ppPtr[i])
183                        ppPtr[i]=0
184                        pSize[i]=0
185                    Else
186                        If isFinish = False Then
187                            OutputDebugString( Ex"heap free missing!\r\n" )
188                        End If
189                    End If
190                End If
191            Next
192        LeaveCriticalSection(CriticalSection)
193    End Sub
194
195    Sub __free(lpMem As VoidPtr)
196        __free_ex( lpMem, False )
197    End Sub
198
199    Sub sweep()
200        EnterCriticalSection(CriticalSection)
201            If iAllSize<limitMemorySize Then
202                'メモリ使用量が上限値を超えていないとき
203                LeaveCriticalSection(CriticalSection)
204                Exit Sub
205            End If
206
207            OutputDebugString( Ex"garbage colletion sweep start!\r\n" )
208
209            Dim hThread As HANDLE
210            Dim ThreadId As DWord
211            hThread=_beginthreadex(NULL,0,AddressOf(SweepOnOtherThread),VarPtr(This),0,ThreadId)
212            WaitForSingleObject(hThread,INFINITE)
213            CloseHandle(hThread)
214        LeaveCriticalSection(CriticalSection)
215    End Sub
216
217Private
218
219    ' 生存検知
220    Function HitTest(pSample As VoidPtr) As Long
221        Dim i As Long
222        For i=0 To ELM(n)
223            If (ppPtr[i] As LONG_PTR)<=(pSample As LONG_PTR) and (pSample As LONG_PTR)<((ppPtr[i] As LONG_PTR)+pSize[i]) Then
224                Return i
225            End If
226        Next
227        Return -1
228    End Function
229
230    ' 指定領域のスキャン
231    Sub Scan(pStartPtr As *LONG_PTR, size As LONG_PTR, pbMark As *Byte)
232        Dim i As Long, count As Long, index As Long
233        count=(size\SizeOf(LONG_PTR)) As Long
234        For i=0 To ELM(count)
235            index=HitTest(pStartPtr[i] As VoidPtr)
236            If index<>-1 Then
237                If pbMark[index]=0 Then
238                    pbMark[index]=1
239
240                    If (pdwFlags[index] and _System_GC_FLAG_ATOMIC)=0 Then
241                        'ヒープ領域がポインタ値を含む可能性があるとき
242                        If ppPtr[index] = 0 Then
243                            'エラー
244
245                        End If
246                        Scan(ppPtr[index] As *LONG_PTR,pSize[index],pbMark)
247                    End If
248                End If
249            End If
250        Next
251    End Sub
252
253    ' ローカル領域をルートに指定してスキャン
254    Sub LocalScan( pbMark As *Byte )
255        Dim Context As CONTEXT
256        Dim NowSp As *LONG_PTR
257        Dim size As LONG_PTR
258        Dim i As Long
259        For i=0 To ELM(_System_pobj_AllThreads->ThreadNum)
260            If _System_pobj_AllThreads->ppobj_Thread[i] Then
261                FillMemory(VarPtr(Context),SizeOf(CONTEXT),0)
262                Context.ContextFlags=CONTEXT_CONTROL
263                If _System_pobj_AllThreads->ppobj_Thread[i]->__GetContext(Context)=0 Then
264                    OutputDebugString(Ex"レジスタ情報の取得に失敗しました。\r\n")
265                End If
266
267#ifdef _WIN64
268                NowSp=Context.Rsp As *LONG_PTR
269#else
270                NowSp=Context.Esp As *LONG_PTR
271#endif
272
273                size=(_System_pobj_AllThreads->pStackBase[i] As LONG_PTR)-(NowSp As LONG_PTR)
274
275                If NowSp = 0 Then
276                    debug
277                    Exit Sub
278                End If
279
280                Scan( NowSp, size, pbMark )
281            End If
282        Next
283    End Sub
284
285    Sub DeleteGarbageMemories( pbMark As *Byte )
286
287        Dim isAllDelete = False
288        If pbMark = NULL Then
289            ' すべてを破棄するとき
290            isAllDelete = True
291            pbMark = _System_calloc( n )
292        End If
293
294        Dim i As Long
295        For i=0 To ELM(n)
296            If pbMark[i]=0 and ppPtr[i]<>0 and (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)=0 Then
297                If ppPtr[i] = 0 Then
298                    If isAllDelete Then
299                        Continue
300                    Else
301                        debug
302                    End If
303                End If
304
305                Dim ptr = ppPtr[i]
306                Dim size = pSize[i]
307
308                ppPtr[i]=0
309                pSize[i]=0
310
311                If (pdwFlags[i] and _System_GC_FLAG_OBJECT) <> 0 Then
312                    /*  ・オブジェクトの個数
313                        ・オブジェクトのサイズ
314                        ・デストラクタの関数ポインタ
315                        を考慮 */
316                    _System_SweepingDelete (ptr + SizeOf( LONG_PTR ) * 3 )
317                Else
318                    iAllSize-=size
319                    HeapFree(_System_hProcessHeap,0,ptr)
320                End If
321            End If
322        Next
323
324        If isAllDelete Then
325            _System_free( pbMark )
326        End If
327
328    End Sub
329
330    Sub DeleteAllGarbageMemories()
331        DeleteGarbageMemories( NULL )
332    End Sub
333
334    Sub Compaction()
335        Dim i As Long, i2 = 0 As Long
336        For i=0 To ELM(n)
337            ppPtr[i2] = ppPtr[i]
338            pSize[i2] = pSize[i]
339            pdwFlags[i2] = pdwFlags[i]
340
341            If ppPtr[i] Then
342                i2++
343            End If
344        Next
345        n = i2
346    End Sub
347
348    ' スウィープ(新規スレッドで呼び出し)
349    Function Cdecl SweepOnOtherThread() As Long
350
351        ' すべてのスレッドを一時停止
352        _System_pobj_AllThreads->SuspendAllThread()
353
354        ' マークリストを生成
355        Dim pbMark = HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,n*SizeOf(Byte)) As *Byte
356
357        ' グローバル領域をルートに指定してスキャン
358        Scan( _System_gc_GlobalRoot_StartPtr, _System_gc_GlobalRoot_Size, pbMark )
359
360        ' ローカル領域をルートに指定してスキャン
361        LocalScan( pbMark )
362
363        ' スウィープ前のメモリサイズを退避
364        Dim iBackAllSize = iAllSize
365
366        ' スウィープ前のメモリオブジェクトの数
367        Dim iBeforeN = n
368
369        '使われていないメモリを解放する
370        DeleteGarbageMemories(pbMark)
371
372        'コンパクション
373        Compaction()
374
375        'マークリストを解放
376        HeapFree(_System_hProcessHeap,0,pbMark)
377
378        If iBackAllSize=iAllSize Then
379            If iAllSize > limitMemorySize Then
380                limitMemorySize = iAllSize
381            End If
382
383            '許容量を拡張する
384            limitMemorySize *= 2
385
386            OutputDebugString( Ex"memory size is extended for gc!\r\n" )
387        End If
388
389        Dim temp[100] As Char
390        wsprintf(temp,Ex"object items         ... %d -> %d  ( %dMB -> %dMB )\r\n",iBeforeN,n, iBackAllSize\1024\1024, iAllSize\1024\1024)
391        OutputDebugString( temp )
392        wsprintf(temp,Ex"limit size of memory ... %d\r\n",limitMemorySize)
393        OutputDebugString( temp )
394        OutputDebugString( Ex"garbage colletion sweep finish!\r\n" )
395
396
397        '-------------------------------------
398        ' すべてのスレッドを再開
399        '-------------------------------------
400        _System_pobj_AllThreads->ResumeAllThread()
401    End Function
402
403    ' 未解放のメモリオブジェクトをトレース
404    Sub DumpMemoryLeaks()
405        Dim isLeak = False
406        Dim i As Long
407        For i=0 To ELM(n)
408            If ppPtr[i] Then
409                If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 Then
410                    If isLeak = False Then
411                        OutputDebugString( Ex"Detected memory leaks!\r\n" )
412                        isLeak = True
413                    End If
414
415                    Dim temp[100] As Char
416                    OutputDebugString( Ex"heap free missing!\r\n" )
417                    wsprintf(temp,Ex"{%d} normal block at &H%08X, %d bytes long.\r\n", i, ppPtr[i], pSize[i])
418                    OutputDebugString( temp )
419                End If
420            End If
421        Next
422
423        If isLeak Then
424            OutputDebugString( Ex"Object dump complete.\r\n" )
425        End If
426
427    End Sub
428
429End Class
430
431'GC管理用の特殊なシステムオブジェクト(デストラクタは最終のタイミングで呼び出されます)
432Dim _System_pGC As *_System_CGarbageCollection
433
434
435
436Function GC_malloc(size As Long) As VoidPtr
437    ' sweep
438    _System_pGC->sweep()
439
440    'allocate
441    Return _System_pGC->__malloc(size,0)
442End Function
443
444Function GC_malloc_atomic(size As Long) As VoidPtr
445    ' sweep
446    _System_pGC->sweep()
447
448    'allocate
449    Return _System_pGC->__malloc(size,_System_GC_FLAG_ATOMIC)
450End Function
451
452Function _System_GC_malloc_ForObject(size As Long) As VoidPtr
453    ' sweep
454    _System_pGC->sweep()
455
456    'allocate
457    Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO)
458End Function
459
460Function _System_GC_malloc_ForObjectPtr(size As Long) As VoidPtr
461    ' sweep
462    _System_pGC->sweep()
463
464    'allocate
465    Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO or _System_GC_FLAG_NEEDFREE)
466End Function
467
468Function _System_GC_free_for_SweepingDelete( ptr As *Object )
469    ' free
470    _System_pGC->__free_ex( ptr, True )
471End Function
Note: See TracBrowser for help on using the repository browser.