443 lines
17 KiB
Plaintext
443 lines
17 KiB
Plaintext
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Las siguientes partes son derechos adquiridos de sus autores individuales.
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* Copyright 2000 Alejandro de Gárate <alex_degarate@hotmail.com>
|
|
* Documentación en Español de:
|
|
* Readme, hb_gcAlloc(), hb_gcFree(), hb_gcLockItem(),
|
|
* hb_gcUnlockItem(), hb_gcCollectAll(), hb_gcItemRef(), HB_GCALL()
|
|
*
|
|
* Copyright 2000 brian Brian Hays <bhays@abacuslaw.com>
|
|
* Documentación en Inglés de:
|
|
* Readme, hb_gcAlloc(), hb_gcFree(), hb_gcLockItem(),
|
|
* hb_gcUnlockItem(), hb_gcCollectAll(), hb_gcItemRef(), HB_GCALL()
|
|
*
|
|
* Vea doc/license.txt por los términos de la licencia.
|
|
*
|
|
*/
|
|
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* Recolector de memoria
|
|
* $CATEGORY$
|
|
* Documentación - Recolector de memoria
|
|
* $ONELINER$
|
|
* Léame con las características de la recoleccion de memoria en Harbour.
|
|
* $DESCRIPTION$
|
|
* El recolector de memoria (garbage collector) usa la siguiente lógica:
|
|
* - primero recolectar todas las ubicaciones de memoria que puedan
|
|
* constituirse en "basura"
|
|
* - luego inspeccionar todas las variables, por si esos bloques están
|
|
* todavía referenciados.
|
|
*
|
|
* Note que sólo arrays, objetos y bloques de código son recolectados
|
|
* porque esos son los únicos tipos de datos que pueden causar:
|
|
* auto-referencias
|
|
* (a[1]:=a)
|
|
* ó referencias circulares:
|
|
* (a[1]:=b; b[1]:=c; c[1]:=a)
|
|
* que no pueden ser apropiadamente desasignadas por un simple conteo
|
|
* de referencia.
|
|
*
|
|
* Como todas las variables en Harbour son almacenadas dentro de algunas
|
|
* tablas disponibles (eval stack, tabla de memvars y array de variables
|
|
* estáticas), entonces chequear si la referencia es todavía activa es
|
|
* bastante fácil y no requiere ningún tratamiento especial durante la
|
|
* la asignación de memoria. Adicionalmente el recolector de memoria
|
|
* inspecciona algunos datos internos usados por la implementación de
|
|
* objetos de Harbour que también almacena algunos valores que pueden
|
|
* contener referencias de memoria. Estos datos son usados para inicia-
|
|
* lizar variables de instancia de la clase, y son almacenadas en
|
|
* variables compartidas por la clase.
|
|
*
|
|
* En casos especiales cuando el valor de una variable de Harbour es
|
|
* almacenada internamente en algún area estática (a nivel de lenguaje C
|
|
* ó asembler), por ejemplo SETKEY() almacena bloques de código que
|
|
* serán evaluados caundo se presione una tecla, el recolector de
|
|
* memoria no será capaz de inspecionar esos valores porque este no
|
|
* conoce su ubicación. Esto podría ocasionar que algunos bloques de
|
|
* memoria sean liberados prematuramente. Para prevenir la prematura
|
|
* desasignación de esos bloques ellos deben ser bloqueados para el
|
|
* recolector de memoria.
|
|
* Para ello se definen distintos estados del bloque de memoria:
|
|
* #define HB_GC_UNLOCKED 0 /* desbloqueado */
|
|
* #define HB_GC_LOCKED 1 /* No recolectar el bloque de memoria */
|
|
* #define HB_GC_USED_FLAG 2 /* bit para la bandera usado/sin uso */
|
|
*
|
|
* El bloque de memoria puede ser bloqueado con hb_gcLockItem(), método
|
|
* recomendado si un ítem de estructura es usado ó la función hb_gcLock()
|
|
* un puntero directo a memoria es usado.
|
|
* El bloque de memoria puede ser desbloqueado por hb_gcUnlockItem() ó
|
|
* hb_gcUnlock().
|
|
*
|
|
* Nótese sin embargo que todas las variables pasadas a una función de
|
|
* bajo nivel son pasadas mediante la pila de evaluación (eval stack),
|
|
* así ellas no necesitan bloquearse durante la llamada a la función.
|
|
* El bloque puede ser requerido, si un valor pasado es copiado dentro
|
|
* de algún area estática para hacerla disponible para otras funciones
|
|
* de bajo nivel, llamadas después de la salida de la función que
|
|
* almacena el valor. Esto es requerido porque el valor es removido de
|
|
* la pila de evaluación después de la llamada a la función y esta no
|
|
* puede seguir siendo referenciada por otras variables.
|
|
*
|
|
* Sin embargo la inspección de todas las variables puede ser una
|
|
* operación de un gran consumo de tiempo. Esto requiere que todos los
|
|
* arrays asignados tengan que ser recorridos a través de todos sus
|
|
* elementos para encontrar más arrays.
|
|
* También todos los bloques de código son inspecionados, en busca de
|
|
* variables locales separadas que ellos estan referenciando. Por esta
|
|
* esta razón, la busqueda por bloques de memoria no referenciados es
|
|
* realizada durante los estados inactivos.
|
|
*
|
|
* El estado inactivo es el estado cuando no hay un código real de la
|
|
* aplicación ejecutándose. Por ejemplo, el código del usuario es
|
|
* detenido durante 0.1 segundo por INKEY(0.1) - Harbour esta chequeando
|
|
* sólo el teclado durante este tiempo. Esto deja sin embargo suficiente
|
|
* tiempo para muchas otras tareas en segundo plano. Una de esas tareas
|
|
* en segundo plano, puede ser la búsqueda de bloques de memoria no
|
|
* referenciados.
|
|
*
|
|
* Asignando memoria </par>
|
|
* -----------------
|
|
*
|
|
* El recolector de memoria, recoge bloques de memoria asignados con
|
|
* llamadas a la función hb_gcAlloc(). La memoria asignada por
|
|
* hb_gcAlloc() debería ser liberada con la función hb_gcFree().
|
|
*
|
|
*
|
|
* Bloqueando memoria </par>
|
|
* ------------------
|
|
*
|
|
* La memoria asignada con hb_gcAlloc() debería ser bloqueada para
|
|
* prevenir una automática liberación como un puntero de memoria si no
|
|
* es almacenado dentro de una variable a nivel de Harbour. Todos los
|
|
* valores de Harbour (items), almacenados internamente en áreas
|
|
* estáticas de lenguaje C deben ser bloqueadas.
|
|
* Vea hb_gcLockItem() y hb_gcUnlockItem() para más información.
|
|
*
|
|
*
|
|
* La recoleción de memoria </par>
|
|
* ------------------------
|
|
*
|
|
* Durante la búsqueda de memoria no referenciada, el recolector de
|
|
* memoria (RM) está usando un algoritmo llamado "mark & sweep", marcar
|
|
* y barrer. Este es realizado en tres etapas:
|
|
*
|
|
* 1) Marcar todos los bloques asignados por el RM con un bandera:
|
|
* "sin uso"
|
|
*
|
|
* 2) barrer (buscar) todos los lugares conocidos y limpiar las banderas
|
|
* sin uso por los bloques de memoria que son referenciados allí;
|
|
*
|
|
* 3) finalizar recolectando por desasignación de todos los bloques de
|
|
* memoria que aún estan marcados como sin uso y que no están bloqueados.
|
|
*
|
|
* Para acelerar las cosas un poco, la etapa de marca es simplificada
|
|
* por la inversión del significado de la bandera "sin uso". Después de
|
|
* la desasignación de los bloques sin uso, todos los bloques todavía
|
|
* activos son marcados con la bandera "usado" así nosotros podemos
|
|
* invertir el significado de esta bandera al estado "sin uso" en la
|
|
* próxima recoleción
|
|
* Todos los bloques de memoria nuevos ó sin bloquear son automáticamente
|
|
* marcados como "sin uso" usando la bandera actual, lo cual asegura que
|
|
* todos los bloques de memoria son marcados con la misma bandera antes
|
|
* de que la etapa de barrido comience.
|
|
*
|
|
* Ver hb_gcCollectAll() y hb_gcItemRef()
|
|
*
|
|
*
|
|
* Llamando al recolector de memoria desde código Harbour </par>
|
|
* ------------------------------------------------------
|
|
*
|
|
* El RM puede ser llamado directamente desde un programa en Harbour.
|
|
* Esto es útil en situaciones donde no hay estados inactivos disponibles
|
|
* ó la aplicación esta trabajando en un bucle sin interacción con el
|
|
* usuario y hay muchas asignaciones de memoria.
|
|
* Vea HB_GCALL() por una explicación de como llamar a esta función
|
|
* desde el código de Harbour.
|
|
* $SEEALSO$
|
|
* hb_gcAlloc(),hb_gcFree(),hb_gcLockItem(),hb_gcUnlockItem(),hb_gcCollectAll(),hb_gcItemRef(),HB_GCALL(),HB_IDLESTATE()
|
|
* $END$
|
|
*/
|
|
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* hb_gcAlloc()
|
|
* $CATEGORY$
|
|
* Recolector de memoria
|
|
* $ONELINER$
|
|
* Asigna memoria que será recolectada por el recolector de memoria.
|
|
* $SYNTAX$
|
|
* #include <hbapi.h>
|
|
* void *hb_gcAlloc( ULONG ulSize, HB_GARBAGE_FUNC_PTR pCleanupFunc );
|
|
* $ARGUMENTS$
|
|
* <ulSize> es el tamaño solicitado del bloque de memoria.
|
|
*
|
|
* <pCleanupFunc> es un Puntero a la función HB_GARBAGE_FUNC que será
|
|
* llamada directamente antes de la liberación del bloque de memoria
|
|
* sin uso ó NULL. Esta función debería liberar toda otra memoria
|
|
* asignada y almacenada dentro del bloque de memoria.
|
|
* Por ejemplo, esta libera todos los items almacenados dentro del array.
|
|
* La función recibe un sólo parámetro: el puntero a la memoria asignada
|
|
* por hb_gcAlloc().
|
|
* $RETURNS$
|
|
* Devuelve un puntero a la memoria asignada ó esta generará un error
|
|
* interno irrecuperable.
|
|
* $DESCRIPTION$
|
|
* hb_gcAlloc() es usada para asignar la memoria que será rastreada por
|
|
* el RM. Este permite una apropiada liberación de memoria en el caso
|
|
* de variables auto-referenciadas ó con referencias cruzadas a nivel de
|
|
* Harbour.
|
|
* La memoria asignada con esta función debería ser liberada con la
|
|
* función hb_gcFree() ó esta será automáticamente desasignada por el
|
|
* RM si no esta bloqueada ó si no esta referenciada por alguna
|
|
* variable a nivel de Harbour.
|
|
* $EXAMPLES$
|
|
* Vea ../source/vm/arrays.c
|
|
*
|
|
* PHB_BASEARRAY pArr = (PHB_BASEARRAY) hb_gcAlloc( sizeof( HB_BASEARRAY),
|
|
* hb_arrayReleaseGarbage );
|
|
* $STATUS$
|
|
* C
|
|
* $COMPLIANCE$
|
|
* Esta función es una extensión de Harbour.
|
|
* $PLATFORMS$
|
|
* Todas
|
|
* $FILES$
|
|
* Archivo fuente: ../source/vm/garbage.c
|
|
* $SEEALSO$
|
|
* hb_gcFree(),hb_gcLockItem(),hb_gcUnlockItem()
|
|
* $END$
|
|
*/
|
|
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* hb_gcFree()
|
|
* $CATEGORY$
|
|
* Recolector de memoria
|
|
* $ONELINER$
|
|
* Libera la memoria que fué asignada con hb_gcAlloc().
|
|
* $SYNTAX$
|
|
* void hb_gcFree( void *pMemoryPtr );
|
|
* $ARGUMENTS$
|
|
* <pMemoryPtr> es el puntero a la memoria a liberar. Este puntero de
|
|
* memoria debe ser asignado con la función hb_gcAlloc().
|
|
* $RETURNS$
|
|
* Nada.
|
|
* $DESCRIPTION$
|
|
* La función hb_gcFree() es usada para liberar la memoria que fué
|
|
* asignada con la función hb_gcAlloc().
|
|
* $EXAMPLES$
|
|
* Vea ../source/vm/arrays.c
|
|
* hb_gcFree( (void *) pBaseArray ); // puntero al array a liberar
|
|
* $STATUS$
|
|
* C
|
|
* $COMPLIANCE$
|
|
* Esta función es una extensión de Harbour.
|
|
* $PLATFORMS$
|
|
* Todas
|
|
* $FILES$
|
|
* Archivo fuente: ../source/vm/garbage.c
|
|
* $SEEALSO$
|
|
* hb_gcAlloc(),hb_gcLockItem(),hb_gcUnlockItem()
|
|
* $END$
|
|
*/
|
|
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* hb_gcLockItem()
|
|
* $CATEGORY$
|
|
* Recolector de memoria
|
|
* $ONELINER$
|
|
* Bloquea la memoria para prevenir la desasignación por el RM.
|
|
* $SYNTAX$
|
|
* void hb_gcLockItem( HB_ITEM_PTR pItem );
|
|
* $ARGUMENTS$
|
|
* <pItem> es el puntero a la estructura item que será bloqueada.
|
|
* El item pasado puede ser de cualquier tipo de datos, aunque arrays
|
|
* objetos y bloques de códigos son bloqueados solamente. Otros tipos de
|
|
* datos no necesitan bloqueo así que ellos son simplemente ignorados.
|
|
* $RETURNS$
|
|
* Nada.
|
|
* $DESCRIPTION$
|
|
* La función hb_gcLockItem() es usada para bloquear el puntero de memoria
|
|
* almacenado en la estructura item pasada. Este suprime la liberación
|
|
* de memoria si el RM no encuentra alguna referencia a este puntero
|
|
* El RM almacena un contador de bloqueo y cada llamada a esta función
|
|
* incrementa el contador. El item es bloqueado si el contador es mayor
|
|
* que cero.
|
|
* $EXAMPLES$
|
|
* Vea ../source/rtl/setkey.c
|
|
* // bloquea un codeblock para prevenir la liberación por el RM
|
|
* hb_gcLockItem( sk_list_tmp-> pAction );
|
|
* $STATUS$
|
|
* C
|
|
* $COMPLIANCE$
|
|
* Esta función es una extensión de Harbour.
|
|
* $PLATFORMS$
|
|
* Todas
|
|
* $FILES$
|
|
* Archivo fuente: ../source/vm/garbage.c
|
|
* $SEEALSO$
|
|
* hb_gcAlloc(),hb_gcFree(),hb_gcUnlockItem()
|
|
* $END$
|
|
*/
|
|
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* hb_gcUnlockItem()
|
|
* $CATEGORY$
|
|
* Recolector de memoria
|
|
* $ONELINER$
|
|
* Desbloquea la memmoria para prevenir la liberación por el RM
|
|
* $SYNTAX$
|
|
* void hb_gcUnlockItem( HB_ITEM_PTR pItem );
|
|
* $ARGUMENTS$
|
|
* <pItem> es el puntero a la estructura item que será bloqueada.
|
|
* El item pasado puede ser de cualquier tipo de datos, aunque arrays
|
|
* objetos y bloques de códigos son bloqueados solamente. Otros tipos de
|
|
* datos no necesitan bloqueo así que ellos son simplemente ignorados.
|
|
* $RETURNS$
|
|
* Nada.
|
|
* $DESCRIPTION$
|
|
* La función hb_gcUnlockItem() es usada para desbloquear el puntero de
|
|
* memoria almacenado en la estructura item pasada, que fué previamente
|
|
* bloqueada con una llamada a hb_gcLockItem(). Esto permite liberar la
|
|
* memoria durante la recolección de memoria sin uso si el RM no encuentra
|
|
* ninguna referencia a este puntero. El RM almacena el contador de
|
|
* bloqueo, cada llamda a esta función decrementa el contador.
|
|
* Esta función no libera la memoria almacenada dentro del item, la
|
|
* memoria debe ser desasignada sin embargo durante la recoleción de
|
|
* memoria sin uso más cercana si el contador de bloqueo es igual a cero
|
|
* y el puntero de memoria no es referenciado por ninguna variable a
|
|
* nivel de Harbour.
|
|
* $EXAMPLES$
|
|
* Vea ../source/rtl/setkey.c
|
|
* hb_gcUnlockItem( sk_list_tmp-> pAction ); // libera el item
|
|
* $STATUS$
|
|
* C
|
|
* $COMPLIANCE$
|
|
* Esta función es una extensión de Harbour.
|
|
* $PLATFORMS$
|
|
* Todas
|
|
* $FILES$
|
|
* Archivo fuente: ../source/vm/garbage.c
|
|
* $SEEALSO$
|
|
* hb_gcAlloc(),hb_gcFree(),hb_gcLockItem()
|
|
* $END$
|
|
*/
|
|
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* hb_gcCollectAll()
|
|
* $CATEGORY$
|
|
* Recolector de memoria
|
|
* $ONELINER$
|
|
* Examina todos los bloques de memoria y libera la memoria sin uso.
|
|
* $SYNTAX$
|
|
* void hb_gcCollectAll( void );
|
|
* $ARGUMENTS$
|
|
* Ninguno.
|
|
* $RETURNS$
|
|
* Nada.
|
|
* $DESCRIPTION$
|
|
* Esta función examina la pila de evaluación, las tablas de memvars,
|
|
* el array de variables estáticas y las tablas de clases creadas en
|
|
* busca de bloques de memoria referenciados. Después de examinar todos
|
|
* los bloques de memoria sin uso y los bloques que no estan bloqueados,
|
|
* son liberados.
|
|
* $STATUS$
|
|
* C
|
|
* $COMPLIANCE$
|
|
* Esta función es una extensión de Harbour.
|
|
* $PLATFORMS$
|
|
* Todas
|
|
* $FILES$
|
|
* Archivo fuente: ../source/vm/garbage.c
|
|
* $SEEALSO$
|
|
* hb_gcAlloc(),hb_gcFree(),hb_gcLockItem(),hb_gcUnlockItem()
|
|
* $END$
|
|
*/
|
|
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* hb_gcItemRef()
|
|
* $CATEGORY$
|
|
* Recolector de memoria
|
|
* $ONELINER$
|
|
* Marca la memoria para prevenir la desasignación por el RM.
|
|
* $SYNTAX$
|
|
* void hb_gcItemRef( HB_ITEM_PTR pItem );
|
|
* $ARGUMENTS$
|
|
* <pItem> es el puntero a la estructura item que será examinada.
|
|
* El item pasado puede ser de cualquier tipo de datos, aunque arrays
|
|
* objetos y bloques de códigos son bloqueados solamente. Otros tipos de
|
|
* datos no necesitan bloqueo así que ellos son simplemente ignorados.
|
|
* $RETURNS$
|
|
* Nada.
|
|
* $DESCRIPTION$
|
|
* El recolector de memoria usa la función hb_gcItemRef() durante la
|
|
* inspección de punteros de memoria referenciados. Esta función chequea
|
|
* el tipo del item pasado y examina recursivamente todos los otros
|
|
* bloques de memoria referenciados por este item, si éste es un array
|
|
* un objeto ó un bloque de código
|
|
*
|
|
* NOTA: Esta función es reservada para el recolector de memoria (RM)
|
|
* solamente. Esta NO debe ser llamada desde el código del usuario
|
|
* llamarla puede causar resultados impredecibles (bloques de
|
|
* memoria referenciados por el item pasado pueden ser liberados
|
|
* prematuramente durante la recoleción de memoria más cercana).
|
|
* $STATUS$
|
|
* C
|
|
* $COMPLIANCE$
|
|
* Esta función es una extensión de Harbour.
|
|
* $PLATFORMS$
|
|
* Todas
|
|
* $FILES$
|
|
* Archivo fuente: ../source/vm/garbage.c
|
|
* $SEEALSO$
|
|
* hb_gcAlloc(),hb_gcFree(),hb_gcLockItem(),hb_gcUnlockItem()
|
|
* $END$
|
|
*/
|
|
|
|
|
|
/* $DOC$
|
|
* $FUNCNAME$
|
|
* HB_GCALL()
|
|
* $CATEGORY$
|
|
* Recolector de memoria
|
|
* $ONELINER$
|
|
* Inspeciona la memoria y libera todos los bloques de memoria sin uso.
|
|
* $SYNTAX$
|
|
* HB_GCALL()
|
|
* $ARGUMENTS$
|
|
* Ninguno
|
|
* $RETURNS$
|
|
* NIL
|
|
* $DESCRIPTION$
|
|
* Esta función libera todos los bloques de memoria que son considerados
|
|
* como "basura".
|
|
* $STATUS$
|
|
* Harbour
|
|
* $COMPLIANCE$
|
|
* Esta función es una extensión de Harbour.
|
|
* $PLATFORMS$
|
|
* Todas
|
|
* $FILES$
|
|
* Archivo fuente: ../source/vm/garbage.c
|
|
* $SEEALSO$
|
|
* hb_gcCollectAll()
|
|
* $END$
|
|
*/
|