Abstürze, Speicherfrage

Alles rund um die Programmierung mit Qt
Antworten
hypolit
Beiträge: 15
Registriert: 28. Mai 2006 11:29

Abstürze, Speicherfrage

Beitrag von hypolit »

Hallo,

ich habe jetzt ein recht umfangreiches Programm zusammen, das mir leider in recht regelmäßigen Abständen abstürzt.

Laut Mac OS Fehlermeldung, die mir oft einen kleinen Backtrace anzeigt, passiert dies häufig bei irgendwelchen new oder malloc Aufrufen.
Daraufhin habe ich meinen Quellcode durchforstet und bin mir eigentlich recht sicher, dass ich jedes new mit entsprechendem delete versehen habe.

Ich frage mich jedoch, wie QT seinen Speicher verwaltet. Muss ich beim Erstellen einer Instanz mit new immer einen parent angeben? Habe meistens einfach 0 übergeben.

Gibt es gute Hilfsprogramme, die einem einen Überblick über Speicherlecks geben oder muss man das Programm schrittweise mit einem Debugger durchlaufen?
Emperor_L0ser
Beiträge: 51
Registriert: 28. Juli 2005 12:26
Kontaktdaten:

Beitrag von Emperor_L0ser »

das ist ganz unterschiedlich, ob ein parent nötig ist oder nicht. widgets zum beispiel benötigen meines wissen nichts. kannst du vll mal einige klasse nennen, in denen du fehler vermutest?
hypolit
Beiträge: 15
Registriert: 28. Mai 2006 11:29

Beitrag von hypolit »

Seit neustem habe ich einen Absturz gleich am Anfang. Ich habe eine Oberfläche mit QDesigner gebaut und starte die als erstes. Hier meine main.cpp:

Code: Alles auswählen

#include "ui_qkal.h"
#include <QApplication>
#include <QMainWindow>
#include "pensiontable.h"


int main(int argc, char* argv[])
{
  QApplication app(argc, argv);
  PensionTable *window = new PensionTable;
  
   window->displayCalendar();
  window->show();
  return app.exec();
  return 1;
}
Und hier Pensiontable, in der es zum Absturz kommt:
Pensiontable.h:

Code: Alles auswählen

#ifndef PENSIONTABLE_H
#define PENSIONTABLE_H
#include <QDate>
#include "ui_qkal.h"
#include "kalender.h"
#include "overview.h"
#include "infoview.h"

class PensionTable : public QMainWindow, private Ui::PensionTable
{
  Q_OBJECT

  public:
  PensionTable(QWidget *parent = 0);
  void addColumn(int position);
  void displayCalendar();
 
 public slots:
  void setMonth(int month);
  void setYear(QDate date);
  void popup();
  void showInfo(int p_col, int p_row);
  void handleInfoChange();
 private:

  Ui::PensionTable ui;
  QDate datum;
   Kalender kaldata;
  OverView *overpop;
  InfoView *infopop;
};

#endif
Hier mein Konstruktor von Pensiontable:
#include "pensiontable.h"
#include <QMessageBox>
PensionTable::PensionTable(QWidget *parent) : QMainWindow(parent)
{

//
setupUi(this);
QFont font("Arial", 14, QFont::Bold);
datum = QDate::currentDate();
tableCalendar->setFont(font);

monthCombo->setCurrentIndex(datum.month()-1);
yearSpin->setDate(datum);
connect(monthCombo, SIGNAL(activated(int)), this, SLOT(setMonth(int)));
connect(yearSpin, SIGNAL(dateChanged(QDate)), this, SLOT(setYear(QDate)));
connect(addPensionButton, SIGNAL(clicked()), this, SLOT(popup()));
connect(tableCalendar, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(showInfo(int, int)));

}
Mache ich bis dahin schon was falsch?
hypolit
Beiträge: 15
Registriert: 28. Mai 2006 11:29

Beitrag von hypolit »

Mir ist aufgefallen, dass die Abstürze am Anfang meist dann kommen, wenn ich das Programm vorher schon einmal gestartet habe. Beim ersten Programmaufruf gibt es in der Regel keine Fehler.
Hier das Backtrace von der Applefehlermeldung:


Thread 0 Crashed:
0 libSystem.B.dylib 0x900036fc szone_malloc + 212
1 libSystem.B.dylib 0x9000334f malloc + 597
2 QtCore 0x00afa0dc QHash<QObject*, QObject**>::createNode(unsigned, QObject* const&, QObject** const&, QHashNode<QObject*, QObject**>**) + 24
3 QtCore 0x00afa652 QHash<QObject*, QObject**>::insertMulti(QObject* const&, QObject** const&) + 100
4 QtCore 0x00acf6a2 QMetaObject::addGuard(QObject**) + 80
5 QtGui 0x0194a799 QMacStylePrivate::addWidget(QWidget*) + 43
6 QtGui 0x0194a9f4 QMacStylePrivate::HIThemePolish(QWidget*) + 32
7 QtGui 0x0183df66 QWidget::event(QEvent*) + 1308
8 QtGui 0x019cc381 QMainWindow::event(QEvent*) + 543
9 QtGui 0x0180ed70 QApplicationPrivate::notify_helper(QObject*, QEvent*) + 322
10 QtGui 0x01814507 QApplication::notify(QObject*, QEvent*) + 1197
11 QtGui 0x01837f9a QWidget::ensurePolished() const + 114
12 QtGui 0x0182774a QLayout::totalMinimumSize() const + 66
13 QtGui 0x01835b08 QWidget::minimumSizeHint() const + 44
14 qkalui 0x000336bc Ui_PensionTable::setupUi(QMainWindow*) + 104 (ui_qkal.h:41)
15 qkalui 0x0001f602 PensionTable::PensionTable[in-charge](QWidget*) + 160 (pensiontable.cpp:8)
16 qkalui 0x0001d2fa main + 66 (main.cpp:10)
17 qkalui 0x00004232 _start + 228 (crt.c:272)
18 qkalui 0x0000414d start + 41
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Dann schau doch einfach mal was in ui_qkal.h:41 gemacht wird. Und debugge das Ganze einfach mal mit gdb oder einem anderen debugger.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
hypolit
Beiträge: 15
Registriert: 28. Mai 2006 11:29

Beitrag von hypolit »

Ich habe jetzt meinen Programmcode etwas umsortiert, indem ich meine QDialogs nur noch mit new erstelle, anstatt sie als festen Bestandteil einer anderen Klasse zu definieren.

Folgendes spuckt gdb nun aus:

Reading symbols for shared libraries ..............................................++...................+ done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0xa1b1c1d7
0x9000375c in szone_malloc ()
(gdb) back
#0 0x9000375c in szone_malloc ()
#1 0x9000334f in malloc ()
#2 0x92f45361 in _GetLayout ()
#3 0x92f4439d in HIWindowFrameView::LayoutChildrenSelf ()
#4 0x92f2140d in HIView::LayoutChildren ()
#5 0x92f4a468 in HIWindowFrameView::AttributesChanged ()
#6 0x92f48c2b in HIWindowFrameView::EventHandler ()
#7 0x92ef88e3 in DispatchEventToHandlers ()
#8 0x92ef7f68 in SendEventToEventTargetInternal ()
#9 0x92ef7e2d in SendEventToEventTargetWithOptions ()
#10 0x92f3a273 in SendSimpleWindowEvent ()
#11 0x92f4a1bb in ChangeWindowAttributes ()
#12 0x0185975a in QWidgetPrivate::setGeometry_sys ()
#13 0x0183cc8f in QWidget::resize ()
#14 0x0003359f in Ui_pensionTable::setupUi (this=0x2017e14, pensionTable=0x2017e00) at ui_qkal.h:31
#15 0x0001f614 in PensionTable::PensionTable (this=0x2017e00, parent=0x0) at pensiontable.cpp:5
#16 0x0001d31e in main (argc=1, argv=0xbffff5cc) at main.cpp:10
(gdb)

An Zeile 32 in ui_qkalui.h befindet sich folgendes:
widget = new QWidget(pensionTable);

pensionTable ist der Name des Widgets, das ich im QDesigner erstellt habe.
Ich kenne mich mit gdb nicht aus, was wäre in solch einem Fall als nächstes zu untersuchen?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Schau doch hin - Zeile 31 ist wichtig (zumindest laut deinem Backtrace)
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
hypolit
Beiträge: 15
Registriert: 28. Mai 2006 11:29

Beitrag von hypolit »

Doof von mir, falsche Linie.

Also im wesentlichen sind die beiden Linien in ui_qkal.h

Code: Alles auswählen

 31: pensionTable->resize(QSize(763, 335).expandedTo(pensionTable->minimumSizeHint()));
  32:  widget = new QWidget(pensionTable);
Das interessant ist, dass das Programm manchmal am Anfang abstürzt und manchmal nicht. Wenn ich Linie 31 auskommentiere, dann liegt der eventuell auftretende Fehler bei Linie 32.

Muss ich mich irgendwie besonders um die Speicherfreigabe bei QT kümmern?
Wie gesagt tritt der Fehler normalerweise auf, nachdem ich das Programm schon einmal gestartet habe.
hypolit
Beiträge: 15
Registriert: 28. Mai 2006 11:29

Beitrag von hypolit »

So, nachdem ich jetzt meinen ganze Code durchforstet habe, bin ich zu der Überzeugung gelangt, dass etwas mit meinen selbstgeschriebenen Klassen nicht in Ordnung war.

Zum Beispiel habe ich eine Klasse um Einträge für einen Kalender einzulesen.
Wenn ich diese in meinen QDialogs nicht mit new aufbaue sondern einfach als als feste Membervariable angebe (kenne nicht den genauen Fachterminus), stürzt das Programm häufig ab. Habe ich nur eine Pointervariable und erstelle und lösche die Klasse nach Bedarf, so treten überhaupt keine Probleme auf.

Ich denke mal, dass meine Klassen sich sonst nicht sauber gelöscht haben, wenn sich das zugehörige QDialog gelöscht hat.
OscarWild
Beiträge: 54
Registriert: 19. Juni 2006 19:59

Beitrag von OscarWild »

hypolit hat geschrieben:Habe ich nur eine Pointervariable und erstelle und lösche die Klasse nach Bedarf, so treten überhaupt keine Probleme auf.
Es sollten niemals Objekte, die von QObject abgeleitet sind, als direkte Members in eine Klasse aufgenommen werden!

QObjects und Derivate registrieren sich ggf. bei einem Parent-QObject, wenn z.B ein Widget einem anderen hinzugefügt wird. Wird das Parent-Object zerstört, zerstört es automatisch auch seine Kinder.

Spätestens beim beenden der Applikation kommt es daher zu einem Absturz:
Das Parent-QObject (PensionTable ) zerstört seine Kinder, darunter auch die Kalender-Instanz, die aber Bestandteil von PensionTable ist!
Antworten