Estoy trabajando en mi camino a través del código de Ferret (puerto de Rubén de Lucene) para resolver un error. El código del hurón es principalmente una extensión C para Ruby. Me encuentro con algunos problemas con el recolector de basura. Me las arreglé para arreglarlo, pero I no entiendo completamente mi solución =) Espero que alguien con más conocimiento de la extensión Ruby y C (este es mi tercer día con Ruby) puede elaborar. Gracias.Recolección de basura con Extensión de Ruby C
Aquí está la situación:
Algunos donde en código C Ferret, estoy volviendo un "token" a Ruby tierra. El código es el siguiente
static VALUE get_token (...)
{
...
RToken *token = ALLOC(RToken);
token->text = rb_str_new2("some text");
return Data_Wrap_Struct(..., &frt_token_mark, &frt_token_free, token);
}
frt_token_mark llama rb_gc_mark (tokens> texto) y frt_token_free simplemente libera el token con conexión (token)
En Ruby, este código se corresponde con lo siguiente:
token = @ input.next
Básicamente, @input se establece en algún objeto, llamando al siguiente método desencadena la llamada a get_token C, que devuelve un objeto token.
En Rubí tierra, que luego hacer algo como w = token.text.scan ('\ w +')
Cuando ejecuto el código dentro de un bucle while 1 (para aislar mi problema), en algunos punto (más o menos cuando mi proceso de rubí mem huella va a 256MB, probablemente cierto umbral GC), ruby muere con errores como
método de exploración llamados en el objeto terminado
O sólo volcado de memoria. Yo creo que token.text fue basura recolectada.
No sé lo suficiente sobre la extensión Ruby C para saber qué ocurre con Data_Wrap_Struct objetos devueltos. Me parece que la asignación en Ruby land, token =, debería crear una referencia a ella.
Mi "solución temporal"/"arreglar" es crear una variable de instancia en el objeto de Ruby mencionado por @input, y almacena el texto token en allí, a obtener una referencia adicional a ella. Así que el código C se parece
RToken *token = ALLOC(RToken);
token->text = rb_str_new2(tk->text);
/* added code: prevent garbage collection */
rb_ivar_set(input, id_curtoken, token->text);
return Data_Wrap_Struct(cToken, &frt_token_mark, &frt_token_free, token);
Así que ahora he creado un "curtoken" en la variable de instancia de entrada y guarda una copia del texto que hay ... Me he encargado de eliminar/borrar esta referencia en la devolución de llamada gratuita de la clase para @input.
Con este código, funciona porque ya no recibo el objeto terminado error.
La solución parece tener sentido para mí - que mantiene una referencia adicional en curtoken a la cadena token.text por lo que no se puede quitar una instancia de token.text hasta la próxima vez @ input.next es llamado (en cuyo momento un token.text diferente reemplaza el antiguo valor en curtoken).
Mi pregunta es: ¿por qué no funcionó antes? ¿No debería Data_Wrap_Structure devolver un objeto que, cuando se le asigna en Ruby land, tiene una referencia válida y no debe ser eliminado por Ruby?
Gracias.
Por cierto, supongo que en C, cuando devuelva Data_Wrap_Struct, realmente debería crear una variable de VALOR, asignarle el resultado de Data_Wrap_Struct, y mantener una referencia de esa variable de VALOR en algún lugar, y esa debería ser la convención normal de devolver un VALOR - necesita mantener una referencia manualmente. Creo que es una solución mejor que lo que he mostrado antes. Pero por favor comenta Gracias. – OverClocked