2009-04-16 17:55 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/source/vm/garbage.c
+ added optional support for automatic GC activation.
It's not enabled by default yet but by compilation with macro
HB_GC_AUTO, f.e. after setting envvar:
set HB_USER_CFLAGS=-DHB_GC_AUTO
Automatic GC activation may be necessary for code which creates
complex variables with cyclic references and does not execute
any other code which may activate idle state GC call. It also
makes unnecessary to explicitly call hb_gcAll() from user code,
f.e. as some type of background task. If some of you were using
code which needed such explicit GC activation then please remove
it and make some tests with Harbour compiled with HB_GC_AUTO macro.
This simple .prg code illustrates the problem. When linked with HVM
without automatic GC it quite fast allocates all available memory
and finished with out of memory error or is interrupted by OS.
When automatic GC is enabled it can work unlimited time period
with some fixed maximum memory usage.
proc main()
local a
while .t.
a:={nil}
a[1]:=a
enddo
return
This commit is contained in:
@@ -8,6 +8,34 @@
|
||||
2009-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
|
||||
*/
|
||||
|
||||
2009-04-16 17:55 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
|
||||
* harbour/source/vm/garbage.c
|
||||
+ added optional support for automatic GC activation.
|
||||
It's not enabled by default yet but by compilation with macro
|
||||
HB_GC_AUTO, f.e. after setting envvar:
|
||||
set HB_USER_CFLAGS=-DHB_GC_AUTO
|
||||
Automatic GC activation may be necessary for code which creates
|
||||
complex variables with cyclic references and does not execute
|
||||
any other code which may activate idle state GC call. It also
|
||||
makes unnecessary to explicitly call hb_gcAll() from user code,
|
||||
f.e. as some type of background task. If some of you were using
|
||||
code which needed such explicit GC activation then please remove
|
||||
it and make some tests with Harbour compiled with HB_GC_AUTO macro.
|
||||
|
||||
This simple .prg code illustrates the problem. When linked with HVM
|
||||
without automatic GC it quite fast allocates all available memory
|
||||
and finished with out of memory error or is interrupted by OS.
|
||||
When automatic GC is enabled it can work unlimited time period
|
||||
with some fixed maximum memory usage.
|
||||
|
||||
proc main()
|
||||
local a
|
||||
while .t.
|
||||
a:={nil}
|
||||
a[1]:=a
|
||||
enddo
|
||||
return
|
||||
|
||||
2009-04-16 00:37 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com)
|
||||
* harbour/contrib/gtqtc/gtqtc.cpp
|
||||
* harbour/contrib/gtqtc/gtqtc.h
|
||||
|
||||
@@ -134,6 +134,18 @@ typedef struct HB_GARBAGE_
|
||||
/* flags stored in 'flags' slot */
|
||||
#define HB_GC_USERSWEEP 8 /* memory block with user defined sweep function */
|
||||
|
||||
#ifdef HB_GC_AUTO
|
||||
/* number of allocated memory blocks */
|
||||
static ULONG s_ulBlocks = 0;
|
||||
/* number of allocated memory blocks after last GC activation */
|
||||
static ULONG s_ulBlocksMarked = 0;
|
||||
# define HB_GC_AUTO_INC ++s_ulBlocks;
|
||||
# define HB_GC_AUTO_DEC --s_ulBlocks;
|
||||
#else
|
||||
# define HB_GC_AUTO_INC
|
||||
# define HB_GC_AUTO_DEC
|
||||
#endif
|
||||
|
||||
/* pointer to memory block that will be checked in next step */
|
||||
static HB_GARBAGE_PTR s_pCurrBlock = NULL;
|
||||
/* memory blocks are stored in linked list with a loop */
|
||||
@@ -206,6 +218,15 @@ void * hb_gcAlloc( ULONG ulSize, HB_GARBAGE_FUNC_PTR pCleanupFunc )
|
||||
pAlloc->flags = 0;
|
||||
|
||||
HB_GC_LOCK
|
||||
#ifdef HB_GC_AUTO
|
||||
if( s_ulBlocks > s_ulBlocksMarked + 100000 )
|
||||
{
|
||||
HB_GC_UNLOCK
|
||||
hb_gcCollectAll( TRUE );
|
||||
HB_GC_LOCK
|
||||
}
|
||||
HB_GC_AUTO_INC
|
||||
#endif
|
||||
hb_gcLink( &s_pCurrBlock, pAlloc );
|
||||
HB_GC_UNLOCK
|
||||
|
||||
@@ -226,7 +247,13 @@ void hb_gcFree( void *pBlock )
|
||||
if( !( pAlloc->used & HB_GC_DELETE ) )
|
||||
{
|
||||
HB_GC_LOCK
|
||||
hb_gcUnlink( pAlloc->locked ? &s_pLockedBlock : &s_pCurrBlock, pAlloc );
|
||||
if( pAlloc->locked )
|
||||
hb_gcUnlink( &s_pLockedBlock, pAlloc );
|
||||
else
|
||||
{
|
||||
hb_gcUnlink( &s_pCurrBlock, pAlloc );
|
||||
HB_GC_AUTO_DEC
|
||||
}
|
||||
HB_GC_UNLOCK
|
||||
|
||||
if( pAlloc->flags & HB_GC_USERSWEEP )
|
||||
@@ -278,7 +305,13 @@ void hb_gcRefFree( void * pBlock )
|
||||
* if cleanup function activate GC
|
||||
*/
|
||||
HB_GC_LOCK
|
||||
hb_gcUnlink( pAlloc->locked ? &s_pLockedBlock : &s_pCurrBlock, pAlloc );
|
||||
if( pAlloc->locked )
|
||||
hb_gcUnlink( &s_pLockedBlock, pAlloc );
|
||||
else
|
||||
{
|
||||
hb_gcUnlink( &s_pCurrBlock, pAlloc );
|
||||
HB_GC_AUTO_DEC
|
||||
}
|
||||
HB_GC_UNLOCK
|
||||
|
||||
pAlloc->used |= HB_GC_DELETE;
|
||||
@@ -323,6 +356,7 @@ void hb_gcRefCheck( void * pBlock )
|
||||
|
||||
HB_GC_LOCK
|
||||
hb_gcLink( &s_pCurrBlock, pAlloc );
|
||||
HB_GC_AUTO_INC
|
||||
HB_GC_UNLOCK
|
||||
|
||||
if( hb_vmRequestQuery() == 0 )
|
||||
@@ -400,6 +434,7 @@ void * hb_gcLock( void * pBlock )
|
||||
{
|
||||
hb_gcUnlink( &s_pCurrBlock, pAlloc );
|
||||
hb_gcLink( &s_pLockedBlock, pAlloc );
|
||||
HB_GC_AUTO_DEC
|
||||
}
|
||||
++pAlloc->locked;
|
||||
HB_GC_UNLOCK
|
||||
@@ -426,6 +461,7 @@ void * hb_gcUnlock( void * pBlock )
|
||||
|
||||
hb_gcUnlink( &s_pLockedBlock, pAlloc );
|
||||
hb_gcLink( &s_pCurrBlock, pAlloc );
|
||||
HB_GC_AUTO_INC
|
||||
}
|
||||
}
|
||||
HB_GC_UNLOCK
|
||||
@@ -713,6 +749,7 @@ void hb_gcCollectAll( BOOL fForce )
|
||||
pDelete->used |= HB_GC_DELETE | HB_GC_DELETELST;
|
||||
hb_gcUnlink( &s_pCurrBlock, pDelete );
|
||||
hb_gcLink( &s_pDeletedBlock, pDelete );
|
||||
HB_GC_AUTO_DEC
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -730,6 +767,11 @@ void hb_gcCollectAll( BOOL fForce )
|
||||
*/
|
||||
s_uUsedFlag ^= HB_GC_USED_FLAG;
|
||||
|
||||
#ifdef HB_GC_AUTO
|
||||
/* store number of marked blocks for automatic GC activation */
|
||||
s_ulBlocksMarked = s_ulBlocks;
|
||||
#endif
|
||||
|
||||
hb_vmResumeThreads();
|
||||
|
||||
/* do we have any deleted blocks? */
|
||||
@@ -757,6 +799,7 @@ void hb_gcCollectAll( BOOL fForce )
|
||||
pDelete->locked = 0;
|
||||
HB_GC_LOCK
|
||||
hb_gcLink( &s_pCurrBlock, pDelete );
|
||||
HB_GC_AUTO_INC
|
||||
HB_GC_UNLOCK
|
||||
if( hb_vmRequestQuery() == 0 )
|
||||
hb_errRT_BASE( EG_DESTRUCTOR, 1301, NULL, "Reference to freed block", 0 );
|
||||
@@ -803,6 +846,7 @@ void hb_gcReleaseAll( void )
|
||||
HB_TRACE( HB_TR_INFO, ( "Release %p", s_pCurrBlock ) );
|
||||
pDelete = s_pCurrBlock;
|
||||
hb_gcUnlink( &s_pCurrBlock, pDelete );
|
||||
HB_GC_AUTO_DEC
|
||||
HB_GARBAGE_FREE( pDelete );
|
||||
|
||||
} while ( s_pCurrBlock );
|
||||
|
||||
Reference in New Issue
Block a user