es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Fuga de memoria en mi proyecto de PyGObject – ¿relacionada con InitiallyUnowned?

Estoy viendo fugas de memoria en mi proyecto PyGObject que no entiendo completamente.

Esperaba poder condensarlo en algún código de ejemplo. Crea instancias de algunas clases de Box en un bucle for. En cada iteración excepto la primera, agrega la nueva caja a la anterior, y también crea una referencia de objeto en la otra dirección.

Entonces esperaría que el recolector de basura sea capaz de limpiar todo ese desorden automáticamente.

Este es el código:

import gi  # cosas de gtk
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk

import weakref

counter = 0

def dec_counter():
    global counter
    counter -= 1

lastbox = None

for i in range(2000):
    newbox = Box()  # ... o Gtk.Box
    if lastbox:
        newbox.foo = lastbox
        lastbox.add(newbox)
    counter += 1
    weakref.finalize(newbox, dec_counter)
    lastbox = newbox

newbox = lastbox = None

gc.collect()
print(counter)

Eso funciona bien si tienes una clase de Box como esta:

class Box:
    def __init__(self):
        self.children = []

    def add(self, item):
        self.children.append(item)

Sin embargo, no funciona aquí cuando se trata de una Box de Gtk.

Parece haber alguna especie de imperfección en cómo la gestión de memoria de Gtk está integrada en Python por PyGObject.
Una lástima si es así, pero tal vez no haya otra opción… Pero al menos necesito entender más sobre la razón y las posibles opciones.

Nota: No estoy buscando poner más esfuerzo manual en limpiar las referencias manualmente en algún momento. Claro, podría hacer eso, pero eso no escala bien si constantemente tienes que agregar toneladas de código complicado pero tedioso para limpiar.

Una cosa más: cuando modifico ligeramente el código del bucle para que recuerde la primera caja, y luego al final llamo a destroy en esa caja, las cosas también funcionan bien.

Un pensamiento que podría estar relacionado, o tal vez sea completa tontería:

En la referencia de la API veo una subclase llamada InitiallyUnowned.
¿Puede que tenga algo que ver con eso?
¿Sucede especialmente cuando creo objetos Gtk y luego los descarto sin usarlos?

Pero si es así, ¿no hay alguna manera de hacer que eso funcione mejor en mi caso? ¿Podría simplemente descartar siempre esa referencia flotante inicial y confiar en tener una referencia en el lado de Python (asumiendo que creo todo en código y no en XML)?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Parece que puede haber un problema con la forma en que PyGObject se integra con el sistema de gestión de memoria de Gtk. Específicamente, al crear instancias de la clase Box de Gtk en un bucle, hay fugas de memoria que no son eliminadas automáticamente por el recolector de basura.

    Una posible solución es limpiar manualmente las referencias, pero esto puede volverse rápidamente tedioso y difícil de escalar. Otra posible solución es llamar a destroy en la primera caja creada en el bucle, lo cual parece solucionar el problema.

    Es posible que la subclase InitiallyUnowned en la referencia de la API de Gtk esté relacionada con este problema, aunque no está claro cómo. Puede valer la pena investigar más para ver si hay alguna forma de mejorar el comportamiento en este caso, por ejemplo, eliminando la referencia flotante inicial y confiando únicamente en las referencias de Python.

Comments are closed.