Russian Qt Forum
Ноябрь 26, 2024, 11:48 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Помогите найти leaks?  (Прочитано 16304 раз)
Nalsur1982
Гость
« : Ноябрь 08, 2007, 09:58 »

Начал заниматься Qt, написал програмку, все перепроверил. Пробовал и так и сяк, но все равно куда-то утекает память. Помогите пожалуйста найти баг?
-------------------------------------------------------------------------------------------------
Код:
main.cpp

#include <QApplication>
#include <QDebug>
//
#include "tcpserver.h"
//
int main(int argc, char **argv)
{
QApplication app(argc, argv);
TcpServer server;

return app.exec();
}
--------------------------------------------------------------------------------------------------------
Код:
tcpserver.h

#ifndef TCPSERVER_H
#define TCPSERVER_H
//
#include <QTcpServer>
#include <QTimer>
//
#include "serverconnection.h"
//
class TcpServer : public QObject
{
Q_OBJECT
public:
TcpServer(QObject *parent = 0);
~TcpServer();

private slots:
void incomingConnection();

protected:
QTcpServer *tcpServer;
ServerConnection *conn;
};
#endif
----------------------------------------------------------------------------------------
Код:
tcpserver.cpp

#include "tcpserver.h"
//
TcpServer::TcpServer( QObject *parent )
: QObject(parent)
{
qDebug() << "TcpServer::TcpServer()";
setObjectName("TcpServer");

tcpServer = new QTcpServer(this);
tcpServer->setObjectName("QTcpServer");
connect(tcpServer, SIGNAL(newConnection()), SLOT(incomingConnection()));
tcpServer->listen(QHostAddress::Any, (quint16)5406);
}

TcpServer::~TcpServer()
{
qDebug() << "TcpServer::~TcpServer()";
delete tcpServer;
}

void TcpServer::incomingConnection()
{
qDebug() << "TcpServer::incomingConnection()";
conn = new ServerConnection(tcpServer->nextPendingConnection(), this->tcpServer);
connect(conn, SIGNAL(finished()), conn, SLOT(deleteLater()));
dumpObjectTree();
}
--------------------------------------------------------------------------------------------------------
Код:
serverconnection.h

#ifndef SERVERCONNECTION_H
#define SERVERCONNECTION_H
//
#include <QThread>
#include <QtNetwork>
//
class ServerConnection : public QThread
{
Q_OBJECT
public:
ServerConnection(QTcpSocket *socket, QObject *parent = 0);
~ServerConnection();
void run();

signals:
void receiveDataFromClient(QHostAddress host);

private slots:
void receiveData();

private:
QTcpSocket *m_pTcpSocket;
quint8 m_startByte;
quint8 m_blockSize;

};
#endif
--------------------------------------------------------------------------------------------------
Код:
serverconnection.cpp

//
#include "serverconnection.h"
//
ServerConnection::ServerConnection( QTcpSocket *socket, QObject *parent)
: QThread(parent), m_pTcpSocket(socket)
{
qDebug() << "ServerConnection::ServerConnection()";
setObjectName(QString("ServerConnection%1").arg(socket->peerPort()));

m_pTcpSocket->setParent(this);
m_pTcpSocket->setObjectName(QString("Socket%1").arg(socket->peerPort()));
connect(m_pTcpSocket, SIGNAL(disconnected()), SLOT(quit()));
connect(m_pTcpSocket, SIGNAL(readyRead()),SLOT(receiveData()));
dumpObjectTree();
start();
}

ServerConnection::~ServerConnection()
{
qDebug() << "ServerConnection::~ServerConnection()";
delete m_pTcpSocket;
}

void ServerConnection::run()
{
qDebug() << "ServerConnection::run()";
exec();
}

void ServerConnection::receiveData()
{
// действия
}

« Последнее редактирование: Ноябрь 08, 2007, 10:17 от Nalsur1982 » Записан
Kainit
Гость
« Ответ #1 : Ноябрь 08, 2007, 10:02 »

conn = new ServerConnection(tcpServer->nextPendingConnection(), this->tcpServer);

1. я не нашёл где делается delete (возможно потому что не очень качественно глядел)
особенно при фразе connect(conn, SIGNAL(finished()), conn, SLOT(deleteLater()));
2. "this->" можно было бы и опустить для красоты
3. Раз вы обнаружили л лик, неужели та софтина что его находит не говорит на какой new он произошёл? Может стоит перейти на BoundChecker?
« Последнее редактирование: Ноябрь 08, 2007, 10:05 от Kainit » Записан
Nalsur1982
Гость
« Ответ #2 : Ноябрь 08, 2007, 10:19 »

Я пок еще чайник в этом деле. Лик обнаружил с помощью менеджера задач, создавая с помщью програмки множественные соединения и разрывая их. По 1 метру на 100 подключений примерно.
 А разве
Цитировать
connect(conn, SIGNAL(finished()), conn, SLOT(deleteLater()));
не удаляет conn. Хотя я и явно пробовал, деструктор вызывается точно.
Записан
Mike
Гость
« Ответ #3 : Ноябрь 08, 2007, 10:21 »

Для ловли утечек памяти (для MS Visual Studio) очень хорошая весчь Visual Leak Detector (http://www.codeproject.com/tools/visualleakdetector.asp)/
Он не такой тяжеловесный как Bounds Checker, да и возможностей по-меньше, но он бесплатный и очень маленький.
Для его использования просто в любой свой заголовочный файл указываешь #include "vld.h", который расположен в его папке include и запускаешь приложение. И в окне Output пишется, где произошло выделение памяти, которая потом не была освобождена. Так же имеется возможность при щелчке по этой строке переходить к данному месту кода.
Вобщем удобная вещь.
Попробуй, может поможет.
Записан
Nalsur1982
Гость
« Ответ #4 : Ноябрь 08, 2007, 10:26 »

А в QDeveloper с MinGW ее можно использовать?
Записан
Mike
Гость
« Ответ #5 : Ноябрь 08, 2007, 10:28 »

Сам не пробовал, поэтому не знаю. Посмотри в его документации. Попробуй, может получиться. Улыбающийся
Записан
ритт
Гость
« Ответ #6 : Ноябрь 08, 2007, 11:15 »

нельзя
Записан
span
Гость
« Ответ #7 : Ноябрь 08, 2007, 11:52 »

Для ловли утечек памяти (для MS Visual Studio) очень хорошая весчь Visual Leak Detector (http://www.codeproject.com/tools/visualleakdetector.asp)/
Он не такой тяжеловесный как Bounds Checker, да и возможностей по-меньше, но он бесплатный и очень маленький.
Для его использования просто в любой свой заголовочный файл указываешь #include "vld.h", который расположен в его папке include и запускаешь приложение. И в окне Output пишется, где произошло выделение памяти, которая потом не была освобождена. Так же имеется возможность при щелчке по этой строке переходить к данному месту кода.
Вобщем удобная вещь.
Попробуй, может поможет.

Давно хотел начать использовать профайлер, или хоть что-то для отлова утечек. Стараюсь, конечно, сразу писать правильный код. Но случается всякое.
Поставил я себе этот Visual Leak Detector. Запустил отладку программы, дождался первого диалога (самописный, в нем я у пользователя акк к базе спрашиваю). Закрыл диалог, программа ругнулась и завершилась.

Вот сижу теперь, пишу сюда. А мне в аутпуте до сих пор сыпятся  собщения, дампы памяти и.т.д.)) Уже 30 000 строк. И как тут понять, где твоя утечка? Большинство сообщений, естественно, указывают на qt\src\... У меня QT собрана в Debug версии.
Пытался использовать встроенный АПИ (VLDDisable / VLDEnable). Не помогает...

Записан
Kainit
Гость
« Ответ #8 : Ноябрь 08, 2007, 12:36 »

Народ что-то чудовищно отдалился от темы. Вроде вопрос был про лик, а не про способы его детектирования.

Цитировать
Я пок еще чайник в этом деле. Лик обнаружил с помощью менеджера задач, создавая с помщью програмки множественные соединения и разрывая их. По 1 метру на 100 подключений примерно.
 А разве
Quote
connect(conn, SIGNAL(finished()), conn, SLOT(deleteLater()));
не удаляет conn. Хотя я и явно пробовал, деструктор вызывается точно.
Я сам чайник, я просто хотел сказать что у тебя finished() непонятно когда вызывается... Такое ощущение что у тебя треды не завершаются (или просто в приведённом фрагменте этого не было)... И в коде треда увидел только exec() из которого ты нигде не выходишь что странно...
Цитировать
You can start the event loop by calling exec(); you can stop it by calling exit() or quit()
« Последнее редактирование: Ноябрь 08, 2007, 12:43 от Kainit » Записан
Icoz
Гость
« Ответ #9 : Ноябрь 08, 2007, 12:48 »

меня смущает строка
Код:
connect(conn, SIGNAL(finished()), conn, SLOT(deleteLater()));
Посмотрел доку, там:
Код:
Note that entering and leaving a new event loop (e.g., by opening a modal dialog) will not perform the deferred deletion; for the object to be deleted, the control must return to the event loop from which deleteLater() was called.
Короче, тебе надо, чтобы закончился разбор сообщений. Только не врубился в каком потоке: твой qtread-потомок или поток основной...
Еще там есть приписка:
Код:
See also destroyed() and QPointer.
 
Посмотри сигнал destroyed() (он вызывается, когда объект уже присмерти...) - убедись, что проходит удаление объекта.
Записан
Nalsur1982
Гость
« Ответ #10 : Ноябрь 08, 2007, 13:11 »

Выхожу из треда когда обрывается соединение
Цитировать
connect(m_pTcpSocket, SIGNAL(disconnected()), SLOT(quit()));
, а finished() вызывается как раз когда тред завершается. Причем все сообщения из конструкторов и деструкторов приходя как надо.
Я пробовал и без DeleteLater(). Делал слот и удалял указатель сендера.
« Последнее редактирование: Ноябрь 08, 2007, 13:23 от Nalsur1982 » Записан
Kainit
Гость
« Ответ #11 : Ноябрь 08, 2007, 13:43 »

Цитировать
connect(m_pTcpSocket, SIGNAL(disconnected()), SLOT(quit()));
И правда... Я попой видимо смотрел.

Собственно,значит всё правильно.
наверное dumpObjectTree(); написано не случайно и наверное вы внимательно глядели на него. Так что именно не удаляется? По логике вещей должно всё быть в порядке...
Можно предположить что по каким-то неведомым причинам сокету может не прийти disconnected(), может каким-то сокетам не вызывается close ()...

Наверное тогда лик живёт в receiveData() в той части что обозначена "// действия"
« Последнее редактирование: Ноябрь 08, 2007, 13:47 от Kainit » Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #12 : Ноябрь 08, 2007, 13:52 »

1) Такой вопрос, зачем нужен ServerConnection (неосновные потоки), если он реально ничего не делает? Толку от него 0!
2) Явно удалять объекты порожденные от QObject у которых есть парент ненужно (delete tcpServer; , etc - это лишнее)
3) Замечание: ServerConnection::ServerConnection( QTcpSocket *socket, QObject *parent). Передавайте дескриптор вместо указателя на сокет. Сам сокет создавайте в run() при этом не указывая парента.

Цитировать
The child of a QObject must always be created in the thread where the parent was created. This implies, among other things, that you should never pass the QThread object (this) as the parent of an object created in the thread (since the QThread object itself was created in another thread).


4) Зачем это наследование class TcpServer : public QObject. Можно сразу наследоваться от QTcpServer


Советую для начала пересмотреть примеры по работу с потоками и сетью. Почитать соответствующме развелы в ассистанте.

ЗЫ: Кстате вот неплохой пример, examples\network\threadedfortuneserver\. Советую с ним разобраться.
« Последнее редактирование: Ноябрь 08, 2007, 13:58 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Nalsur1982
Гость
« Ответ #13 : Ноябрь 08, 2007, 14:19 »

Проверял программу именно с пустой процедурой receiveData(), чтобы не было "наводок".
Сначала реализовывал связь с использованием дескрипторов и как в асистенте и как в примере на этом форуме в теме про QTcpSocket и QThread, но утечка была еще больше. В этом варианте ее поменьше.

ServrConnection используеться для приема, отправки и проверки прав доступа удаленного хоста к серверу. Далее информация как QByteArray поступает на вход класса-анализатора протокола (хочу чтобы класс не зависил от физики связи TCP/IP или COM)

Цитировать
Явно удалять объекты порожденные от QObject у которых есть парент ненужно (delete tcpServer; , etc - это лишнее)
явно я их и не удалял, но из-за ликов перестраховался.

Уже мозг дымиться Улыбающийся
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #14 : Ноябрь 08, 2007, 15:30 »

В том коде что вы привели ServrConnection не выполняет абсолютно никаких полезных действий. Поток просто создаеться и весит. Ничего более. Работа с потоками поставлена неверно.

Экзампл examples\network\threadedfortuneserver выполнят аналогичные действия вашим. Советую переделать ваш код по такому же принципу.

Следующий момент, можно ли превести код метода dumpObjectTree()? Возможно проблема именно в нем. Этот метод вызываеться в нескольких местах, интересно на него взглянуть.

И наконец, попробуйте закоментировать все в методе void TcpServer::incomingConnection() и посмотреть, будел ли течь память илинет.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.115 секунд. Запросов: 22.