On Fri, May 28, 2010 at 01:39:43PM +0200, Alessandro Dentella wrote:
> Grazie Marco per la dritta, 
> 
> On Fri, May 28, 2010 at 12:19:12PM +0200, Marco Giusti wrote:
> > On Fri, May 28, 2010 at 10:25:51AM +0200, Alessandro Dentella wrote:
[...]
> > 
> > Vediamo un po' tutti i possibili problemi che possono sorgere:
> > 
> > 1. il metodo `delete_event_cb` elimina il riferimento alla finestra ma
> > il metodo può essere ancora chiamato dal padre e non essendoci più
> > riferimenti a `self.w`...
> 
> non mi è chiaro, il padre sarebbe l'istanza stessa? Eliminata 'w', che
> tramite le callback aveva riferimenti (forti, direi) a 'g', g dovrebbe
> sparire per me...
> 
> Vedo che la grossa differenza fra la mia e la tua versione è nel fatto che io
> ho una connect a 'delete_event' che tu non hai, entrambe però eliminiamo con
> una chiamata diretta a destroy() la finestra, che quindi emette un
> 'delete_event'. Quindi io passo due volte dal metodo 'delete_event_cb', la
> seconda volta il metodo non ha più self.w... ho capito!

quell'esempio è solo una diversa implementazione del tuo esempio, se
devi fare una comparazione con il tuo, controlla l'altro. nel secondo
esempio l'unica differenza è l'attributo `self.objects` che contiene i
riferimenti forti agli oggetti.

> Probabimente la dipendenza dal numero di finestre create è poi dovuta a
> ritardi di gtk che è alle prese con il rendering delle finestre. La 10.04
> era simulata in VirtualBox quindi più lenta e quindi mi dava l'errore già a
> 3/4 finestre.

credo che questo sia un effetto aleatorio, che dipende da quando il gc
entra in funzione, dal SO, dalla quantità di ram, ecc.

> > 2. gli unici riferimenti che hai agli oggetti `G` sono dei riferimenti
> > deboli. a questo punto credo che tu debba andare a vedere come i
> > riferimenti deboli siano implementati in pygtk. non sono molto preparato
> > qui ma sicuramente il problema è questo. Accanto a `self.windows`
> > affianca un'altra lista: `self.objects` con riferimenti forti, vedrai
> > che a questo punti non hai più di questi problemi.
> > 
> > per quanto ne so' la gestione dei riferimenti in pygtk è pensata per, ad
> > eccezione di casi particolari, potersene dimenticare. nel momento in cui
> > non ci sono più riferimenti python ad un oggetto gobject, questo viene
> > deallocato.
> 
> Il tutto è nato proprio perché vedo crescere a dismisura l'occupazione di
> ram in una applicazione GTK e sto pensando di rimpiazzare riferimenti forti
> con riferimenti deboli. Questo test era nato proprio dall'esigenza di
> vedere se riuscivo a tenere la RAM sotto controllo.
> 
> promesso che apro altre discussioni per la ram...

secondo me non è il modo migliore per procedere, a meno che tu non sia
certo che il memory leak dipenda proprio dalle gtk e non da un bug nel
tuo programma.

weakref diventa molto utile quando devi conservare in memoria dati
binari di dimenzioni considerevoli come un'immagine. in quel caso ha
senso usare i riferimenti deboli: se il SO richiede di liberare la
memoria il riferimento viene perso ma lo si può comunque andare a
recuperare i dati. es:

        class Img(object):

                _img = None
                @property
                def img(self):
                        if self._img is None:
                                self._img = open(self.filename).read()
                        return self._img

                def __init__(self, filename):
                        self.filename = filename

> > ps. ti allego la versione modificata.
> > 
> > pps. la gerarchia che crei è con soli due livelli, perché allora non usi
> > due classi distinte? ti allego la versione modificata
> 
> Perché nell'esempio reale alcune istanze della classe Mask gemmano altre
> istanze della classe Mask, poi nell'esempio ho cambiato il look solo perché
> non fosse troppo fuorviante vedere interfacce uguali.

ti allego un altro esempio che forse ti spiegherà meglio. lancialo due
volte, la prima così come è, la seconda volta commenta tutti i
riferimenti a `self.objects` che ti ho segnato. usando le callback puoi
vedere quando gli oggetti sono deallocati.

infatti quando tu hai l'eccezione:

        AttributeError: 'G' object has no attribute 'title'

puoi notare come gli attributi dell'oggetto siano stati tutti liberati.

ciao
m.

-- 
C'è un'ape che se posa
su un bottone di rosa:
lo succhia e se ne va...
Tutto sommato, la felicità
è una piccola cosa.
        
                -- Trilussa, Felicità
import os
import gc
import sys
import weakref
import gtk


def callback(wref):
    print wref
    obj = wref()
    print obj
    print type(obj)
    print dir(obj)


class G(object):
    def __init__(self, title=''):
        self.windows = []
        self.objects = [] # XXX: commenta qui
        self.title = title
        self.w = gtk.Window()
        self.w.set_title(title)
        self.h = gtk.HBox()
        self.kill_button = gtk.Button("kill")
        self.crea_button = gtk.Button(title and "Finestra %s" % title or "crea %s finestre" % n)
        self.w.add(self.h)
        self.h.add(self.crea_button)
        self.h.add(self.kill_button)
        self.w.show_all()
        self.w.connect('delete-event', self.delete_event_cb)
        self.kill_button.connect('clicked', self.clicked_cb)
        self.crea_button.connect('clicked', self.crea_molte_finestre)

    def delete_event_cb(self, win, ev=None):
        self.w.get_toplevel().destroy()
        del self.w

    def crea_molte_finestre(self, win, ev=None):
        if self.title:
            return
        for i in range(n):
            obj = G(title=str(i))
            r = weakref.ref(obj, callback)
            self.windows += [r]
            self.objects.append(obj) # XXX: commenta qui

    def clicked_cb(self, win):
        if self.title:
            self.delete_event_cb(win)
        else:
            for g in self.windows:
                if g():
                    g().delete_event_cb(None, None)
                #if g:  # se non usi weakref
                #    g.delete_event_cb(None, None)
            self.windows = []
            del self.objects[:] # XXX: commenta qui


if __name__ == '__main__' :

    if len(sys.argv) == 2:
        n = int(sys.argv[1])
    else:
        n = 10
    obj = G()
    obj.w.connect('destroy', gtk.main_quit)
    try:
        gtk.main()
    except KeyboardInterrupt:
        sys.exit()
_______________________________________________
Python mailing list
Python@lists.python.it
http://lists.python.it/mailman/listinfo/python

Rispondere a