Реклама

вопрос по ICMP

ICMP

вот тут https://evileg.com/post/167/
помогите пожалуйста пробую вашу программу а именно ту часть которая выполняет Ping я использую ее в цыкле так при повторном запуске потихоньку утекает память(ОЗУ) посмотрел вроде идет в конце free(ReplyBuffer); // Освобождаем память но не помогает очень нужно т.к. я не сильно разбираюсь(учусь только) программировать я в ВК добавился к вам можно и в нем ответить Черпаченко Станислав. Заранее очень благодарен на сайте у вас зарегался
  • #
  • 21 ноября 2016 г. 20:33
Ну. Проверил я этот код в цикле и не заметил утечек памяти.
Функция free() используется для освобождения памяти, которая была выделена функцией malloc().
Те переменные, что есть в обработчике нажатия кнопки, сохраняются в стеке, поэтому они существуют локально в данном методе, ну или в теле цикла, если в цикл поместить.
Так что, у Вас имеется ошибка где-то помимо данного кода.
прошу прощения, что не уточнил, возможно это важно! цикл запускается, в потоке, чтобы не вис интерфейс. Причем если запускать пустой поток, только с пустым циклом или заменить в этом цикле пинг(значение задержки) на случайное число, утечка не идет(память не растет постоянно, пока работает поток, немного увеличивается, потом срабатывает диструктор класса, запущенного в потоке и память опять возвращается на значение, до запуска потока), а если в цикле еще делать пинг адреса, то память растет постоянно в течении дня. делается программа мониторинга(доступности устройств в локальной сети и это критично).
А не могли бы привести кусок кода, где инициализируется поток, и то место, где идёт работа с пингом. С проблемным участком.

[spoiler=”Неполный код программы(много строк потому под споллер”]
в заголовочном файле
class MainWidget : public QWidget
{
Q_OBJECT

public:
explicit MainWidget(QWidget *parent=0);
~MainWidget();
RaschetU *ras;

};

class PingGL : public QObject
{
Q_OBJECT

public:
explicit PingGL(QString adres, int mas2, int vrOg, QObject* parent=0);
~PingGL();

public: int getValue() const { return pingTek;}
private: int pingTek=1;

signals:
public slots:
int slotPerDannye(QString adres, int mas2, int vrOg);
};

class RaschetU : public QObject
{
Q_OBJECT

public:
explicit RaschetU(QString adr[],QString zvu[],QString zve[],QString maxping[],QString inf0[],QObject* parent=0);

QString *adrPotok, *zvuPotok, *zvePotok, *maxpingPotok, *inf0Potok;

~RaschetU();
________________________________

MainWidget::MainWidget()
{
………………..
………………..
………………..
ras=0;
sozdRAS();
PotoK->start();

reading();
}

void MainWidget::sozdRAS ()
{
if (ras)
{
qDebug () << “поток RAS существует – деллаю quit()”;
while(ras)
{
PotoK->quit();
QCoreApplication::processEvents();
}
}

PotoK = new QThread;
ras= new RaschetU(adr, zvu, zve, maxping, inf0); // передаю массивы в поток через конструктор
ras->moveToThread(PotoK);

connect (PotoK, SIGNAL(started()), ras, SLOT(run()));
connect (ras, SIGNAL(finished()),PotoK, SLOT(quit()));
connect (ras, SIGNAL(finished()),ras, SLOT(deleteLater()));
connect (PotoK, SIGNAL(finished()),PotoK, SLOT(deleteLater()));
connect (ras, SIGNAL(destroyed(QObject*)),this, SLOT(ObnulitUk15()),Qt::QueuedConnection);

connect (ras, SIGNAL(signalpinAdr()), this, SLOT(slotpinAdr()),Qt::QueuedConnection);
connect (ras, SIGNAL(signalDobZap(QString,QString,QString,QString)), this, SLOT(DobZap(QString,QString,QString,QString)),Qt::QueuedConnection);
connect (ras, SIGNAL(signalPrevy(int,QString)), this, SLOT(slotPrevy(int,QString)),Qt::QueuedConnection);
connect (ras, SIGNAL(signalPingTekMas(int,QString)), this, SLOT(slotPingTekMas(int,QString)),Qt::QueuedConnection);
connect (ras, SIGNAL(signalZapChas(QDateTime,QDateTime)), this, SLOT(slotChas(QDateTime,QDateTime)),Qt::QueuedConnection);

connect (ras, SIGNAL(signalObnProgr(int,QString)), this, SLOT(slotObnProgr(int,QString)),Qt::QueuedConnection);
connect (ras, SIGNAL(signalZapTimera(int,int,QString, QString, QString, QString)), this, SLOT(slotZapTimera(int,int,QString, QString, QString, QString)),Qt::QueuedConnection);
connect (ras, SIGNAL(runReadingL()), this, SLOT(readingL()),Qt::QueuedConnection);
connect (ras, SIGNAL(runReading()), this, SLOT(reading()),Qt::QueuedConnection);
connect (ras, SIGNAL(signalOBNNras(int)),grafiksWindow, SLOT(slotOBN(int)),Qt::QueuedConnection);

}

MainWidget::reading()
{
считывание массивов
……………..
ReadinL();
}

MainWidget::reading()
{
рисование виджетов
……………..
текст сейчас не важен т.к. рисование отключил чтобы ловить утечку в остальном коде
}
RaschetU::RaschetU(QString adr[],QString zvu[],QString zve[],QString maxping[],QString inf0[],QObject *parent) : QObject(parent)
{
adrPotok=adr;
zvuPotok=zvu;
zvePotok=zve;
maxpingPotok=maxping;
inf0Potok=inf0;
}
RaschetU::~RaschetU()
{
qDebug () << “Запущен диструктор RAS”;
stop=false;
return;
}
void RaschetU::run ()
{
qDebug () << “Запущен run (Начало ПОТОКА)”;
if (comPing==1)
{
runzikl(pov);
}

}

qDebug () << “отработал run (Конец ПОТОКА)”;
qDebug () << “”;
emit finished();
}

void RaschetU::runzikl (int pov)
{
QDateTime vrTek123,vr1123,vr2123,vr3123,vr4123,nowD123,nowD0123,vrNach123, now3123;

QString nowDStr0123=””,nowDStr123=””,maxPingZv123=””, maxPing123=””;
QString noPing123=””, noPingZv123=””,tabB123=””,nam123=””,adres123=””;
int obnKn=0,razz=0,oRaz=0, Sec123=0,proz123=0;

qDebug () << “начало Runzikl”;

if ((stop==false)&&(otlRead==0))
{
tabB123=””;
zapPi=1;
nowD0123 = QDateTime::currentDateTime();
nowD0123 = nowD0123.addSecs(-1);
nowDStr0123 = nowD0123.toString(“yyyy-MM-dd hh:mm:ss”);
}

if ((desSek==false)&&(stop==false)&&(otlRead==0))
{

// qDebug () << ” время записи нулей в таблицу = ” << 0;

if ((stop==false)&&(otlRead==0))for (int k123=0; k123<= razm-1; k123++)
{
if((stop==true)||(otlRead==1))
{
qDebug () << “останов по СТОП 2″;
emit finished();
break;
}

nam123=”Запись нулей”;
proz123=(k123+1)*100/(razm);

emit signalObnProgr(proz123,nam123);

if (opov==0)
{
emit signalDobZap(adrPotok[k123],QString(“%1”).arg(“0″),”minutes”, nowDStr0123);

emit signalDobZap(adrPotok[k123],QString(“%1”).arg(“0″),”hours”, nowDStr0123);
}

emit signalPrevy(k123,”0″);

}
desSek=true;
vrNach123 = QDateTime::currentDateTime();
vr1123 = QDateTime::currentDateTime().addMonths(-1); // минус месяц
vr2123=vrNach123.addSecs(33); // плюс час от начала

vr2Str=””;
vrNachStr=””;

}

if ((stop==false)&&(otlRead==0))
{
if (vr2Str!=””)
{
vr2123 = QDateTime::fromString(vr2Str, “dd.MM.yyyy HH:mm:ss”);

}
if (vrNachStr!=””)
{
vrNach123= QDateTime::fromString(vrNachStr, “dd.MM.yyyy HH:mm:ss”);
}

vrTek123 = QDateTime::currentDateTime(); //текущее время
vr3123 = vrTek123.addSecs(60); //плюс минута
vr4123 = QDateTime::currentDateTime().addSecs(-28800); //минус 8 часов

nowD123 = QDateTime::currentDateTime();
nowDStr123 = nowD123.toString(“yyyy-MM-dd hh:mm:ss”);

obnKn=0;

if (vrTek123>=vr2123)
{
emit signalZapChas(vrNach123,vr2123);
vr2123=vr2123.addSecs(33);
vrNach123=vrNach123.addSecs(33);
}

now3123 = QDateTime::currentDateTime();

noPing123= now3123.toString(“-hh:mm:ss- || dd//MM//yyyy”)+” || Адрес(а):\n”; noPingZv123=now3123.toString(“-hh:mm:ss- || dd//MM//yyyy”)+” || Адрес(а):\n”;
maxPingZv123=now3123.toString(“-hh:mm:ss- || dd//MM//yyyy”)+” || Адрес(а) с повышенным PinG’ом:\n”; maxPing123=now3123.toString(“-hh:mm:ss- || dd//MM//yyyy”)+” || Адрес(а) с повышенным PinG’ом:\n”;
}
if ((stop==false)&&(otlRead==0))for (int i123=0; i123<= razm-1; i123++)

{
if((stop==true)||(otlRead==1))
{
qDebug () << “останов по СТОП 3″;
emit finished();
break;
}

if ((stop==false)&&(otlRead==0))
{

nam123=”PinG Базы ip адресов”;
proz123=(i123+1)*100/(razm);

emit signalObnProgr(proz123,nam123);

adres123=adrPotok[i123];

mas=3;

classPingGL = new PingGL(adres123, mas2, 2000);

pingTek=classPingGL->getValue();

delete classPingGL;

// qsrand(QTime(0,0,0).msecsTo(QTime::currentTime())); // временная замена пингу чтобы исключить утечку в самом пинге
// Sleep(30);
// pingTek=randomBetween(0,1000);
// Sleep(1);

// QCoreApplication::processEvents();

if((stop==true)||(otlRead==1))
{
qDebug () << “останов по СТОП 4″;
emit finished();
break;
}

prev=0;

if (pingTek==0)
{
prev=1;

emit signalPrevy(i123,”1″);

if (zvuPotok[i123]==”1″) noPingZv123+=inf0Potok[i123]+” “+adrPotok[i123]+”\n”;
if ((zvePotok[i123]==”1″)&&(zvuPotok[i123]==”0″)) noPing123+=inf0Potok[i123]+” “+adrPotok[i123]+”\n”;

}
else if (pingTek>=maxpingPotok[i123].toInt())
{
prev=1;
// prevyPotok[i123]=”2″;
emit signalPrevy(i123,”2″);

if (zvuPotok[i123]==”1″) maxPingZv123+=inf0Potok[i123]+” “+adrPotok[i123]+” время ответа>”+maxpingPotok[i123]+” mS\n”;
if ((zvePotok[i123]==”1″)&&(zvuPotok[i123]==”0″)) maxPing123+=inf0Potok[i123]+” “+adrPotok[i123]+” время ответа>”+maxpingPotok[i123]+” mS\n”;
}
else
{
emit signalPrevy(i123,”0″);
}

emit signalPingTekMas(i123, QString(“%1”).arg(pingTek));

emit signalDobZap(adrPotok[i123],QString(“%1″).arg(pingTek),”minutes”, nowDStr123);
}
}
if ((stop==false)&&(otlRead==0))
{
nam123=”PinG Базы окончен”;
proz123=0;
emit signalObnProgr(proz123,nam123);

nam123=””;

if (noPingZv123.length()>40)
{
noPingZv123+=”не отвечают на PinG”;
}

if (noPing123.length()>40)
{
noPing123+=”не отвечают на PinG”;
}

if(opov==0)opov=1;

obnKn=1;

vrTek123 = QDateTime::currentDateTime();
razz = vrTek123.toTime_t()-vrNach123.toTime_t();
oRaz= 60-(razz-((razz/60)*60));

if(vrTek123>vr3123)
{
Sec123= 60-vrTek123.toString(“ss”).toInt();
qDebug () << “уже прошло больше минуты”;
qDebug () << “Sec123=” << Sec123;
qDebug () << “запускаю таймер на t = 0”;

emit signalZapTimera(1,1, noPingZv123, noPing123, maxPingZv123, maxPing123);

if((stop==true)||(otlRead==1))
{
qDebug () << “останов по СТОП 5”;
emit finished();
}

}

if(vrTek123<=vr3123)
{
razz=vr3123.toTime_t()-vrTek123.toTime_t();

// emit signalZapTimera(razz,1, noPingZv123, noPing123, maxPingZv123, maxPing123);

emit signalZapTimera(4,1, noPingZv123, noPing123, maxPingZv123, maxPing123);// временно для тестирования

if((stop==true)||(otlRead==1))
{
qDebug () << “останов по СТОП 6”;
emit finished();
}

}

qDebug () << “конец Runzikl”;

}

return;
}

void MainWidget::slotZapTimera(int t,int nTimera,QString noPingZv123, QString noPing123, QString maxPingZv123, QString maxPing123)
{
while(ras)
{
// qDebug () << “Ждем окончания ПОТОКА”;
QCoreApplication::processEvents();
}
if(!ras) qDebug () << “ПОТОК закрылся!!!!!!!!!!!!!!!!!!!”;

if (nTimera==1)
{

// qDebug () << “таймер перезапущен на ” << t << ” секунд”;
if(timer->isActive())timer->stop();
timer->start(t*1000);
}
if (mas==3)
{
qDebug () << “”;
qDebug () << “Запущен noPing”;
// slotnoPing(noPingZv123,noPing123,maxPingZv123,maxPing123);
}

}

void MainWidget::update ()
{

if(timer->isActive())timer->stop();

if (pov1==1)
{
zapPi=1;
if (postrGr1==1)
{
stopRisM=false;
emit signalOBNN(1);

}

if (mas==3)
{

ui->pushButton_3->setText(“СтоП”);
ui->pushButton->setEnabled(false);
ui->checkBox->setEnabled(false);
}
if (mas==0)
{
ui->pushButton->setText(“СтоП”);
ui->pushButton_3->setEnabled(false);
}
comPing=1;

// qDebug () <<“ras перезапущен из update 1 pov1=” << pov1;
sozdRAS();
PotoK->start();

}

if (pov1==0)
{
if(ras)
{
PotoK->quit();
PotoK->wait();
while(ras)
{
QCoreApplication::processEvents();
}
}

if (mas==3)
{
ui->pushButton_3->setText(“Ping массива”);
ui->pushButton->setEnabled(true);

}
if (mas==0)
{
ui->pushButton->setText(“Ping адреса”);
ui->pushButton_3->setEnabled(true);
}
comPing=0;
ui->checkBox->setEnabled(true);
}

qDebug () <<“отработал update”;
}

void MainWidget::DobZap(QString ipadres, QString ping, QString tabliza, QString nowDStr123)
{

qDebug () << “начал работу СЛОТ Добавления”;

sozSoed(“Dannye01″,”Dannye.sqlite”);

QSqlDatabase *db=0;
db = &QSqlDatabase::database(“Dannye01”);
db->open();

QSqlQuery query10= QSqlQuery(*db);

query10.prepare(QString(“INSERT INTO ‘%1’ (datatime, ipadres, ping ) VALUES (:DateToday, :Ipadres, :Ping)”).arg(tabliza));

query10.bindValue(“:DateToday”, nowDStr123);
query10.bindValue(“:Ipadres”,ipadres);
query10.bindValue(“:Ping”,ping);

if (!query10.exec()){QCoreApplication::processEvents();
qDebug() <<“ошибка добавления записи в талицу ” << tabliza;
qDebug() << query10.lastError().text();

}

else qDebug() <<“Запись добавлена в таблицу: ” << tabliza;
QCoreApplication::processEvents();

db->commit();
query10.finish();
query10.clear();

db->close();
db=0;

// zakSoed(“Dannye01”); // если раскомментировать то вылет краш

qDebug () << “закончил работу СЛОТ Добавления”;

}

void MainWidget::sozSoed(QString name, QString fName)
{
QSqlDatabase *dbOSN=0;

// qDebug () << QSqlDatabase::connectionNames ();
if(QSqlDatabase::contains(name))
{
dbOSN = &QSqlDatabase::database(name);
qDebug () << “в MainWidget соединение ” << name << ” уже создано”;
// qDebug () << QSqlDatabase::connectionNames ();
}
else
{
// ———- Подключение к БД
QString path;
path = QCoreApplication::applicationDirPath();
{
dbOSN = &QSqlDatabase::addDatabase(“QSQLITE”,name);
// dbOSN->setHostName(“127.0.0.1″);
dbOSN->setDatabaseName(path+”/”+fName);
// dbOSN->setDatabaseName(path+”/Dannye.sqlite”);
// dbOSN->setUserName(“root”);
// dbOSN->setPassword(“root”);

if (!dbOSN->open())
{
qDebug () << dbOSN->lastError().text();
oshbase=1;
return;
}
else
{
// qDebug () << “”;
// qDebug () << “в MainWidget подключение ” << name << ” Создано”;
// qDebug () << QSqlDatabase::connectionNames ();
oshbase=0;
}
}
}
dbOSN=0;
}

void MainWidget::zakSoed(QString name)
{
if(QSqlDatabase::contains(name))
{
QSqlDatabase *dbOSN=0;
dbOSN = &QSqlDatabase::database(name);
dbOSN->commit();
dbOSN->close();
QSqlDatabase::removeDatabase(name);
dbOSN=0;
qDebug() << “в MainWidget подключение ” << name << ” Удалено”;
// qDebug () << “”;
// qDebug() << “AfterDelete” << QSqlDatabase::database().connectionNames();
}
else qDebug() << “в MainWidget Подключение ” << name << ” не существует”;
}

[/spoiler]

пытался засунуть под споллер не вышло. ping в этом коде засунул в отдельный класс думал так уйдет утечка до этого код Pinga был в классе который выполняется в потоке в void RaschetU::startping(adres)

Какое безобразие… Зачем же названия методов и переменных транслитом?

А если конкретно по делу, то вижу, что под переменную raz выделяется память.
При этом в коде есть условия, которые проверяют, что переменная эта существует или нет. Значит допускается, что переменная может и не существовать, возможно, что даже она пересоздаётся при каких-то условиях. То есть под неё снова выделяется память. Вот только я так и не увидел оператора delete, который бы удалял её. Если этот объект где-то в программе пересоздаётся, но при этом не удаляется, то вероятно, что там может быть утечка памяти.

Впрочем метод DobZap, тоже генерирует утечку памяти. В жизненном цикле программы достаточно один раз открыть подключение к базе данных. А потом просто работать с базой данных. У меня на сайте порядка 12 статей, где описывается работа с базой данных. Посмотрите те статьи, где идёт работа с таблицами. Там есть класс DataBase, можете от него отталкиваться. Воспользуйтесь поиском по сайту.

А у Вас DobZap выделяет память, открывая базу данных, и не освобождает память при окончании работы с базой данных. Базу данных в таком случае надо закрывать, а память освобождать.
Ладно бы, если в стеке всё сохранялось при работе в методе, тогда бы автоматически память была бы освобождена, а у Вас всё кидается в heap (кучу), а память не освобождается.

Полагаю, что там ещё можно наковырять проблемных мест. Но тут всё нужно переписывать. Бросайте этот кипишь с лишь бы написать побыстрее и планомерно изучите по отдельности все вопросы, а именно:
– работа с памятью, heap, стек, указатели, оператор new.
– работа с базой данных.
– работа с потоками.
– и только потом уже PING ICMP WinAPI

P/S/ Не приравнивайте указатель к нулю. В стандарте с++ уже давно для этого используется nullptr.
То есть raz = 0; – это плохо.
Правильно raz = nullptr;

nullptr исправил везде и сделал многое из того, что вы написали исправить, и много еще ошибок нашел и исправил, но суть не в том…
я запустил пустой поток, по кругу, прогонял программу в таком режиме, 3 часа. количество занимаемой памяти не увеличилось. добавил в поток ТОЛЬКО ping и пошла утечка. не сильная, но есть за 8 часов утекло 600 Килобайт не много но для программы которая выполняется постоянно это критично. Потому все же прошу, помочь Вас в выявлении утечки, в коде по по ICMP. Заранее благодарен за помощь.
Люди на форумах подсказали что нужно в конце pinga нужно перед очисткой памяти попробовать это
IcmpCloseHandle(hIcmpFile); но к сожалению это тоже не помогло

Попробуйте вот такой вариант интегрировать в свою программу.

HANDLE icmpHandle = IcmpCreateFile();
int size_buffer = 32;
char *sendBuffer = new char[size_buffer];
IPAddr netaddr = inet_addr("192.168.0.1");
unsigned long replySize = sizeof(ICMP_ECHO_REPLY) + size_buffer;
LPVOID replyBuffer = (void*) malloc(replySize);
 
DWORD response = IcmpSendEcho(icmpHandle,netaddr , sendBuffer, size_buffer, NULL, replyBuffer, replySize, 1000);
printf("Response from Send Echo is: %d\n", response);
if (response>0)
{
    PICMP_ECHO_REPLY reply = (PICMP_ECHO_REPLY)replyBuffer;
    printf("RTT: %d\n", reply->RoundTripTime);
    IcmpCloseHandle(icmpHandle);
    delete replyBuffer, sendBuffer;
}
else
{
    printf("Error %d\n", GetLastError());
    IcmpCloseHandle(icmpHandle);
    delete replyBuffer, sendBuffer;
}

 

Реклама

Ответы

Только авторизованные пользователи могут отвечать на форуме.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь

C++ - Тест 002. Константы

  • Результат - 50 баллов

C++ - Тест 005. Структуры и Классы

  • Результат - 66 баллов

C++ - Тест 001. Первая программа и типы данных

  • Результат - 53 баллов
Последние комментарии
  • EVILEG
  • 23 июля 2017 г. 16:10

Использование модуля QtTextToSpeech для синтеза речи

Лично я простого не знаю способа. В обоих случаях понадобится использовать сторонние библиотеки.В случае с pdf - это будет либа, которая работает с pdf, какой-нибудь poppler-qt.В случае же ...

  • BlinCT
  • 23 июля 2017 г. 14:41

Qt/C++ - Урок 068. Hello World с использованием системы сборки CMAKE в CLion

При том подходе в разработке что ведет JetBrains, скоро CLion обгонит QtCreator. Даже сейчас он в некоторых местах по функционалу уже обходит QtCreator(работа с VCS уже превосходит в удобстве)...

Использование модуля QtTextToSpeech для синтеза речи

Если вы знаете простой способ для извлечения текста из pdf или djv файлов напишите в ответе.

  • EVILEG
  • 13 июля 2017 г. 2:12

Qt/C++ - Урок 023. Перетаскивание QGraphicsItem на QGraphicsScene мышью

Ну например так можете сделать.void MoveItem::mousePressEvent(QGraphicsSceneMouseEvent *event){ if (QApplication::mouseButtons() == Qt::RightButton) { this->deleteLa...

  • Mark
  • 13 июля 2017 г. 1:26

Qt/C++ - Урок 023. Перетаскивание QGraphicsItem на QGraphicsScene мышью

Подскажите пожалуйста как в данном проекте по перетаскиванию организовать удаление объекта со scene методом delete item, допустим при щелчке ПКМ по объекту QGraphicsScene. Мои попытки оказалис...

Сейчас обсуждают на форуме
  • EVILEG
  • 23 июля 2017 г. 19:44

Передача данных из цикла С++ в QML

День добрый. Под QQmlContext , подразумеваете, что регистрировали dataport в контексте QML , и через Connections устанавливали обработчик для сигнала ...

  • EVILEG
  • 23 июля 2017 г. 19:32

Как правильно хранить настройки подключения к БД

Я тут накидал пример простого шифрования с использованием XOR шифрования, посмотрите. Для начала Вам это должно подойти, а потом уже можно будет искать и более сложные способы шифро...

  • crak20
  • 23 июля 2017 г. 7:20

Передача нескольких переменных по UDP

Нужен пример передачи и приема переменных (например int, double, QString) по сети UDP. Как для одной переменной так и структуры. P.S новичок

Как реализовать отправку e-mail

Подключил SMTP из-под Qt при отправке сообщения QAbstractSocket::waitForBytesWritten() is not allowed in UnconnectedStateQAbstractSocket::waitForBytesWritten() is not allowe...

  • EVILEG
  • 21 июля 2017 г. 19:48

Обрезка участка изображения с сохранением пропорций

Так, а под сохранением пропорций подразумевается сохранение пропорций самой области выделения? то есть тот квадрат выделения, который перемещаете? Если есть какой код или наброски мыслей...