#c #qt
#c #qt
Вопрос:
У меня есть небольшая программа на C на основе Qt, и эта программа просто записывает вектор в файл, пока я не нажму кнопку «СТОП».
В Qt designer я просто нажимаю кнопку, меняю текст на «STOP» и называю объект «button».
Проблема в том, что когда я проверяю использование памяти программой с помощью команды watch в терминале, я вижу, что свободная память со временем уменьшается, и нажатие на кнопку на это не влияет. Оно возвращается к своему первоначальному состоянию, только если я закрываю приложение.
test.pro :
#-------------------------------------------------
#
# Project created by QtCreator 2016-10-12T13:56:45
#
#-------------------------------------------------
QT = core gui
greaterThan(QT_MAJOR_VERSION, 4): QT = widgets
QMAKE_CXXFLAGS = -std=c 11
QMAKE_CXXFLAGS = -D_GLIBCXX_USE_CXX11_ABI=0
QMAKE_CXXFLAGS = -pthread
TARGET = Test
TEMPLATE = app
SOURCES = main.cpp
mainwindow.cpp
writer.cpp
HEADERS = mainwindow.h
writer.h
FORMS = mainwindow.ui
mainwindow.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <writer.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_stopButton_clicked();
void on_startButton_clicked();
private:
Ui::MainWindow *ui;
writer *w;
};
#endif // MAINWINDOW_H
writer.h :
#ifndef WRITER_H
#define WRITER_H
#include <iostream>
#include <fstream>
#include <iterator>
#include <string>
#include <locale>
#include <sstream>
#include <thread>
#include <atomic>
#include <vector>
#define COUNTER_FILENAME "data_counter.txt"
#define DATA_PREFIX "data_no"
#define DATA_EXTENSION ".csv"
class writer
{
public:
// For labeling
unsigned int label_id;
bool label;
// Start writing frame features in a file
void write();
// Stop writing
void stopWriting();
// Default demo constructor, sets up the frame thread which will process frame data in a seperate thread
explicit writer();
// Default demo destructor, flags that the frame thread should stop and waits for the frame thread to join
~writer();
protected:
std::unique_ptr< std::thread > frameThread;
std::atomic< bool > stopFrameThread;
std::vector< float > frameFeatures;
std::string data_filename;
};
#endif // WRITER_H
main.cpp :
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp :
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
w(new writer())
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete w;
delete ui;
}
void MainWindow::on_stopButton_clicked()
{
w->stopWriting();
}
void MainWindow::on_startButton_clicked()
{
w->write();
}
writer.cpp :
#include "writer.h"
writer::writer() :
label_id( 0 ),
label( false )
{
stopFrameThread = false;
// Resize the vector to put all frame features
frameFeatures.resize( 1743, 0.0 );
}
writer::~writer()
{
stopWriting();
}
void writer::write()
{
// Setup the frame thread
stopFrameThread = false;
// Create a new thread to retrieve all features of each frame
frameThread = std::unique_ptr< std::thread >( new std::thread( [ this ](){
// Read from counter file to get counter value
std::string counter;
std::ifstream counter_in (COUNTER_FILENAME);
if( counter_in.is_open() ){
std::getline( counter_in, counter );
counter_in.close();
}else{
counter = "0";
}
// Convert the counter into an integer
int c;
std::stringstream( counter ) >> c;
// Compute data filename
data_filename = DATA_PREFIX counter "_id" applicant_id DATA_EXTENSION;
std::ofstream data_file( data_filename );
if( data_file.is_open() ){
// Start the main processing loop
while( ! stopFrameThread ){
for(int index = 0; index < 1743; index ){
frameFeatures[ index ] = index;
}
for(std::vector< float >::iterator it = frameFeatures.begin(); it != frameFeatures.end(); it){
data_file << " " std::to_string( *it );
}
data_file << "n";
}
// Close the data file
data_file.close();
// Write incremented counter value on counter file
std::ofstream counter_out (COUNTER_FILENAME);
if( counter_out.is_open() ){
counter_out << c;
counter_out.close();
}else{
std::cerr << "Unable to write on counter filen";
}
}else{
std::cerr << "Unable to open the data filen";
}
} ) );
}
void writer::stopWriting()
{
// Flag that the frame thread should stop
stopFrameThread = true;
// Wait for the frame thread to stop
if( frameThread ){
if( frameThread->joinable() ){
frameThread->join();
}
}
}
Спасибо за любую помощь.
Комментарии:
1. Проблема в том, что когда я проверяю использование памяти программой с помощью команды watch в терминале — вы не должны использовать инструменты ОС, чтобы определить, действительно ли ваша программа на C пропускает память. Диспетчер кучи среды выполнения C может удерживать память на случай, если потребуются дополнительные выделения. Добавьте кнопку «Пуск» и посмотрите, продолжает ли увеличиваться объем памяти при повторной записи вектора. Если объем памяти не увеличивается, это подтверждает, что диспетчер кучи работает так, как задумано, и явной утечки памяти нет.
2. Вы имеете в виду добавить кнопку для запуска потока вместо запуска его с помощью конструктора?
3. Нет, я имею в виду запуск, остановку, а затем повторный запуск в том же запуске вашего приложения. Это второй запуск, который определит, действительно ли у вас утечка памяти. Если вы видите, что объем памяти начинает увеличиваться с той же скоростью, что и при первоначальном запуске, то, вероятно, вы можете привести доводы в пользу утечки памяти. Если вы не видите такого увеличения, то это подтверждает, что диспетчер кучи выполняет свою работу.
4. Я сделал, как вы сказали, и когда я останавливаю запуск, использование памяти остается на том же уровне, но когда я (повторно) запускаю, оно продолжает увеличиваться: ( Итак, это означает, что у меня утечка памяти, не так ли? Откуда это может быть?
Ответ №1:
Прошло некоторое время с тех пор, как я исправил проблему, но я подумал, что должен написать это здесь на случай, если кто-то столкнется с подобной проблемой.
В коде не было ни ошибки, ни утечки памяти. Программа работает отлично. Проблема заключалась в том, что процесс создания новых векторов был быстрее, чем при записи в файл.
Я решил это, создав два отдельных потока для ускорения процесса. Первый поток создаст векторы и сохранит их в буфере. Второй поток возьмет вектор из этого буфера и запишет его.