2016-06-15 53 views
5

Ho appena fornito una risposta per la domanda this e ho voluto fornire un esempio funzionante quando ho notato che l'istanza di nuova creazione QMimeData restituita da QListModel::mimeData() non verrà eliminata fino alla chiusura dell'applicazione.Perdita di memoria in Qt5? Come si può eliminare QMimeData?

Quindi questo non è un perdita di memoria reale dal Qt gestisce tutte le istanze QMimeData allo spegnimento, ma si avrà solo a trascinare lungo & goccia abbastanza e mettere il contenuto giusto nei vostri dati MIME per far correre la memoria piena.

Mi sono perso qualcosa? C'è un modo per dire a Qt di eliminare le istanze QMimeData non appena non sono più necessarie?

Si prega di notare:

So che ogni istanza di QMimeData viene eliminato da Qt automaticamente al termine del programma. Il mio problema qui non è una vera perdita di memoria, come riportato da valgrind o cppcheck ma sembra che le istanze multiple e potenzialmente molto grandi di QMimeData non vengano ripulite in fase di runtime che fa esplodere anche il consumo di memoria.

Esempio di codice:

#include <QtWidgets> 
#include <iostream> 

struct TrackedMimeData : public QMimeData { 
    TrackedMimeData(const QString & text) { 
     std::cout << this << std::endl; 
     setText(text); 
    } 
    ~TrackedMimeData() { 
     std::cout << "~" << this << std::endl; 
    } 
}; 

struct MyListWidget : QListWidget { 
    MyListWidget() { 
     setDragEnabled(true); 
     addItem("item1"); 
     addItem("item2"); 
    } 
    QMimeData * mimeData(const QList<QListWidgetItem *>) const override { 
     return new TrackedMimeData("hello"); 
    } 
}; 

int main(int argsc, char *argsv[]) { 
    QApplication application(argsc, argsv); 
    MyListWidget gui; 
    gui.show(); 
    return application.exec(); 
} 

uscita Esempio simile a questo:

0xa58750 
0xa4e0f0 
~0xa4e0f0 
0xa3c6c0 
~0xa3c6c0 
0xa51880 
0xa5ecd0 
0xa31f50 
0xa57db0 
0xa5afc0 
~0xa5afc0 
0xa5aa70 
~0xa5aa70 
------ CLOSE WINDOW 
~0xa58750 
~0xa51880 
~0xa5ecd0 
~0xa31f50 
~0xa57db0 

I distruttori vengono chiamati prima chiudere l'applicazione solo quando ha accettato il get goccia.

Btw. Sono su un Qt domestico 5.6 @ 1fcdb6cafcf - su un computer e su 5.6.0-19.fc23 Fedora 23 precompilato su un altro. Quindi dubito che sia solo uno stato di sviluppo temporaneo.

+0

'QMimeData' eredita' QObject' e memorizza internamente i propri dati come 'QVector' di stringhe e' coppie QVariant'. Ha gli stessi limiti di gestione della memoria rispetto ad altre esperienze di classe derivate da 'QObject'. –

+0

'cppcheck' non ha trovato nulla in questo esempio perché l'istanza' QMimeData' viene eliminata alla fine. Ma fino ad allora avrei potuto immagazzinare gigabyte di dati in migliaia di istanze di nuove istanze di 'QMimeData' - che è - lo ammetto - non una perdita di memoria classica. – frans

+1

In realtà stai vedendo un consumo eccessivo di memoria, o semplicemente preoccupato che possa accadere? –

risposta

2

C'è una perdita di memoria solo se si dimentica di cancellare il puntatore restituito da mimeData(). Devi gestire la proprietà come con qualsiasi puntatore.

Per esempio, se si passa il mimeData() restituito puntatore ad un oggetto utilizzando QDragsetMimeData(), egli avrà la proprietà di esso, e si prenderà cura di eliminarlo al termine dell'operazione di trascinamento. In questo caso non ci sono perdite di memoria.

See: http://doc.qt.io/qt-5/qdrag.html#setMimeData

+0

Uso un 'QListWidget' che deriva da' QAbstractItemView' e crea/gestisce l'oggetto 'QDrag'. Creo solo il 'QMimeData' che poi viene posseduto dall'oggetto' QDrag' al quale non ho accesso. – frans

+1

Sì, ma la documentazione dice che QDrag :: setMimeData passa la proprietà all'oggetto QDrag. Ciò significa che l'oggetto QMimeData verrà eliminato quando QDrag viene eliminato. – galinette

+0

Ok, ma l'oggetto 'QDrag' non viene eliminato in tempo - correggerò questo dettaglio nella mia domanda ma il problema è lo stesso. – frans

1

Si dovrebbe accadere, se non lo è, allora è un bug - non c'è niente che tu possa fare a questo proposito, a parte la segnalazione, se non è stata ancora pubblicata.

Non riesco a riprodurlo su OS X con Qt 5.6. Può essere specifico della piattaforma o di un bug già risolto in una vecchia versione di Qt. Non appena rilascio il pulsante del mouse alla fine del trascinamento, i dati del mimo vengono cancellati. Lo stack di chiamate quando viene eseguito il distruttore ha il distruttore QDrag chiamato dal ciclo degli eventi tramite da qualche parte. Ho usato il tuo codice testualmente.

Sidebar: Potrebbe essere reso solo un po 'più minimale, se si voleva davvero il più breve possibile. Ecco cosa ho ottenuto, anche se sono d'accordo che per lo più divida i capelli.La tua domanda supera il 99% di altre domande entro il fornendo un esempio funzionante: grandi soddisfazioni per questo! Le cose che ritengo importanti per brevità sono:

  1. Inclusione dell'intero modulo Qt necessario.
  2. Uso di qDebug anziché std::cout & al, salva un inclusione ed è più in stile Qt.
  3. Gli specifi che di accesso non sono importanti se si utilizza struct in ogni caso.
  4. In generale, i distruttori sono virtuali nella classe base pubblica, oppure non possono mai essere senza cedimento. Quindi non devi sillabarlo.

Ho codice di esempio in cui non lo seguo, ovviamente. Mi piace chiamarlo il codice legacy :)

#include <QtWidgets> 

struct TrackedMimeData : QMimeData { 
    TrackedMimeData(const QString & text) { 
     qDebug() << this; 
     setText(text); 
    } 
    ~TrackedMimeData() { 
     qDebug() << "~" << this; 
    } 
}; 

struct MyListWidget : QListWidget { 
    MyListWidget() { 
     setDragEnabled(true); 
     addItem("item1"); 
     addItem("item2"); 
    } 
    QMimeData * mimeData(const QList<QListWidgetItem *>) const override { 
     return new TrackedMimeData("hello"); 
    } 
}; 

int main(int argsc, char *argsv[]) { 
    QApplication application(argsc, argsv); 
    MyListWidget gui; 
    gui.show(); 
    return application.exec(); 
} 
+0

sfortunatamente non vedo alcun output da qDebug - né sul terminale né su QtCreator.Ma l'output con 'cout' dimostra che il distruttore non viene chiamato (nel mio caso) – frans

+0

@frans Weird ... Che piattaforma e versione di Qt è attiva? È sicuramente un bug. Si prega di segnalare se non segnalato già. –

+0

Ritorno dalle vacanze Ora ho creato https://bugreports.qt.io/browse/QTBUG-54667 – frans