Seite 1 von 1

Abstürze, Speicherfrage

Verfasst: 13. Juni 2006 21:55
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?

Verfasst: 13. Juni 2006 23:51
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?

Verfasst: 14. Juni 2006 10:08
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?

Verfasst: 14. Juni 2006 10:52
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

Verfasst: 14. Juni 2006 10:55
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.

Verfasst: 14. Juni 2006 11:24
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?

Verfasst: 14. Juni 2006 11:31
von Christian81
Schau doch hin - Zeile 31 ist wichtig (zumindest laut deinem Backtrace)

Verfasst: 14. Juni 2006 11:43
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.

Verfasst: 14. Juni 2006 18:20
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.

Verfasst: 21. Juni 2006 11:36
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!