Recolector de memoria
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
- -----------------
- 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
- ------------------
- 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
- ------------------------
- 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
- ------------------------------------------------------
- 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.
- See Also