6

Solo por pura casualidad, he decidido crear un Scheme binding to libpython para que pueda incrustar Python en programas Scheme. Ya puedo llamar a la API C de Python, pero realmente no he pensado en la gestión de memoria.¿Hay problemas de conteo de Python/recolección de basura al tratar con el código C?

La manera en que funciona el FFI de mzscheme es que puedo llamar a una función, y si esa función devuelve un puntero a PyObject, entonces puedo hacer que aumente automáticamente el recuento de referencias. Luego, puedo registrar un finalizador que disminuirá el recuento de referencias cuando el objeto Scheme obtiene basura recolectada. Miré documentation for reference counting, y no veo ningún problema con esto a primera vista (aunque en algunos casos puede ser subóptimo). ¿Hay algún truco que me falta?

Además, estoy teniendo problemas para hacer cara o cruz del cyclic garbage collector documentation. ¿Qué cosas tendré que tener en cuenta aquí? En particular, ¿cómo hago que Python sepa que tengo una referencia a algo para que no lo recopile mientras lo sigo usando?

Respuesta

7

Su enlace a http://docs.python.org/extending/extending.html#reference-counts es el lugar correcto. Las secciones de Extender e Incorporar y Python/C API de la documentación son las que explicarán cómo usar la API de C.

El recuento de referencias es una de las partes molestas del uso de la API de C. Lo principal es mantener todo en orden: Dependiendo de la función de API a la que llamas, puedes poseer o no la referencia al objeto que obtienes. Tenga cuidado de comprender si lo posee (y por lo tanto no puede olvidar DECREFIRLO o dárselo a algo que lo robe) o lo está pidiendo prestado (y debe INCREMENTARLO para conservarlo y posiblemente para usarlo durante su función). Los errores más comunes que involucran esto son 1) recordar incorrectamente si posee una referencia devuelta por una función en particular y 2) creer que es seguro tomar prestada una referencia por un tiempo más largo que usted.

No tiene que hacer nada especial para el recolector de basura cíclico. Está ahí para reparar un defecto en el conteo de referencias y no requiere acceso directo.

+0

Entonces ... Python utiliza el recuento de referencias * y * un recolector de basura para la estructura cíclica? Esa es una falla bastante importante. El tipo de diseño. En cualquier caso, esto parece que hará las cosas mucho más "divertidas" para Jason, si los valores que participan en un ciclo de python están expuestos a un esquema. –

+0

Buena información. Mientras INCREFIÉ todo cuando lo obtenga y DECREF todo cuando termine con él, ¿debería estar bien? ¿O hay algún problema con el que me encuentre? –

+2

@Jason, solo INCREF * borrowed * references. Algunas funciones devuelven * nuevas * referencias que ya están INCREF'ed. INCREFARlos resultaría en una pérdida de memoria. –

3

El mayor problema que conozco con el conteo de ref y el C API es el __del__ cosa. Cuando tiene una referencia prestada a algo, cree que puede escapar sin INCREFiar porque no abandona el GIL mientras usa esa referencia. Pero, si termina borrando un objeto (por ejemplo, eliminándolo de una lista), es posible que active una llamada __del__, lo que puede quitar la referencia de la que está pidiendo prestado. Muy engañoso.

Si INCREF (y luego DECREF, por supuesto) todas las referencias prestadas tan pronto como las obtenga, no debería haber ningún problema.

Cuestiones relacionadas