- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个更大的项目,有一个 GUI,我想在后台管理一些文件。我已经为此任务和运行时实现了一个新线程,一切都很好。但是一旦我退出应用程序visual-leak-detector
发现 3-7 个内存泄漏。
我分离了我的线程代码并创建了一个新项目以使用最少的代码示例来检查这一点,但我仍然无法解决我的问题。
我觉得跟主程序的事件循环有关系。也许循环不处理最后的事件来删除我的线程类和线程本身。因为我在析构函数中停止并退出线程。但我不确定这个。
这是我的最小代码:线程类.hpp:
#include <QObject>
#include <QDebug>
class ThreadClass : public QObject {
Q_OBJECT
public:
explicit ThreadClass() {}
virtual ~ThreadClass(){
qDebug() << "ThreadClass Destructor";
}
signals:
// emit finished for event loop
void finished();
public slots:
// scan and index all files in lib folder
void scanAll(){
for(long i = 0; i < 10000; i++){
for (long k = 0; k < 1000000; k++);
if(i%500 == 0)
qDebug() << "thread: " << i;
}
}
// finish event loop and terminate
void stop(){
// will be processed after scanall is finished
qDebug() << "STOP SIGNAL --> EMIT FINSIHED";
emit finished();
}
};
线程处理程序.hpp:
#include <QObject>
#include <QThread>
#include "threadclass.hpp"
class ThreadHandler : public QObject {
Q_OBJECT
public:
explicit ThreadHandler(QObject *parent = 0) : parent(parent), my_thread(Q_NULLPTR) {}
virtual ~ThreadHandler() {
// TODO Check!
// I think I don't have to delete the threads, because delete later
// on finish signal. Maybe I just have to wait, but then how do I
// check, if thread is not finished? Do I need to make a bool var again?
if (my_thread != Q_NULLPTR && my_thread->isRunning())
{
emit stopThread();
//my_thread->quit();
my_thread->wait();
//delete my_thread;
}
qDebug() << "ThreadHandler Destructor";
my_thread->dumpObjectInfo();
}
void startThread(){
if (my_thread == Q_NULLPTR)
{
my_thread = new QThread;
ThreadClass *my_threaded_class = new ThreadClass();
my_threaded_class->moveToThread(my_thread);
// start and finish
QObject::connect(my_thread, &QThread::started, my_threaded_class, &ThreadClass::scanAll);
QObject::connect(this, &ThreadHandler::stopThread, my_threaded_class, &ThreadClass::stop);
// finish cascade
// https://stackoverflow.com/a/21597042/6411540
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
QObject::connect(my_threaded_class, &ThreadClass::destroyed, my_thread, &QThread::quit);
QObject::connect(my_thread, &QThread::finished, my_thread, &QThread::deleteLater);
my_thread->start();
}
}
signals:
void stopThread();
private:
QObject *parent;
QThread* my_thread;
};
main.cpp 很糟糕,但似乎足以很好地模拟我的主程序的行为:
#include <QCoreApplication>
#include <QTime>
#include <QDebug>
#include "threadhandler.hpp"
#include <vld.h>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
ThreadHandler *th = new ThreadHandler();
th->startThread();
// wait (main gui programm)
QTime dieTime= QTime::currentTime().addSecs(5);
while (QTime::currentTime() < dieTime) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
qDebug() << "DELETE TH";
delete th;
qDebug() << "FINISH ALL EVENTS";
QCoreApplication::processEvents(QEventLoop::AllEvents, 500);
qDebug() << "QUIT";
QCoreApplication::quit();
qDebug() << "CLOSE APP";
// pause console
getchar();
// return a.exec();
}
这是 VLD 的输出:
WARNING: Visual Leak Detector detected memory leaks!
...
turns out this is very boring and uninteresting
...
Visual Leak Detector detected 3 memory leaks (228 bytes).
Largest number used: 608 bytes.
Total allocations: 608 bytes.
Visual Leak Detector is now exiting.
The program '[8708] SOMinimalExampleThreads.exe' has exited with code 0 (0x0).
更新 1: 我添加了 qDebug() << "ThreadClass Destructor";
到 ThreadClass
的析构函数我的新输出如下所示:
...
thread: 9996
thread: 9997
thread: 9998
thread: 9999
ThreadHandler Destructor
FINISH ALL EVENTS
CLOSE APP
现在很明显,我的线程类的析构函数从未被调用过,因此在空白中丢失了。但为什么这不起作用?
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
更新 2: 我在 ThreadHandler 中发现了一个问题:
emit stopThread();
my_thread->quit(); // <-- stops the event loop and therefore no deletelater
my_thread->wait();
我删除了 my_thread->quit()
现在调用了 ThreadClass 的析构函数,但是 my_thread->wait()
永远不会结束。
最佳答案
当 ThreadHandler
的析构函数从主线程发出 stopThread
时,Qt 通过发送一个事件进入工作线程的事件循环(也称为排队连接)。这意味着当发出此信号时,工作人员的事件循环需要准备好接收新事件(因为您依赖它来执行适当的清理)。但是,正如您已经发现的那样,调用 thread->quit()
可能会导致事件循环提前退出(在工作线程调用 ThreadClass 之前): :stop
,因此不会发出信号 ThreadClass::finished
)。您可能想要检查这个重现我正在谈论的行为的最小示例的输出:
#include <QtCore>
/// lives in a background thread, has a slot that receives an integer on which
/// some work needs to be done
struct WorkerObject : QObject {
Q_OBJECT
public:
using QObject::QObject;
Q_SLOT void doWork(int x) {
// heavy work in background thread
QThread::msleep(100);
qDebug() << "working with " << x << " ...";
}
};
/// lives in the main thread, has a signal that should be connected to the
/// worker's doWork slot; to offload some work to the background thread
struct ControllerObject : QObject {
Q_OBJECT
public:
using QObject::QObject;
Q_SIGNAL void sendWork(int x);
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QThread thread;
WorkerObject workerObj;
workerObj.moveToThread(&thread);
// quit application when worker thread finishes
QObject::connect(&thread, &QThread::finished, &a, &QCoreApplication::quit);
thread.start();
ControllerObject controllerObj;
QObject::connect(&controllerObj, &ControllerObject::sendWork, &workerObj,
&WorkerObject::doWork);
for (int i = 0; i < 100; i++) {
QThread::msleep(1);
// call thread.quit() when i is equal to 10
if (i == 10) {
thread.quit();
}
controllerObj.sendWork(i);
}
return a.exec();
}
#include "main.moc"
在我的机器上,这是一个可能的输出:
working with 0 ...
working with 1 ...
working with 2 ...
working with 3 ...
请注意,尽管 thread.quit()
在主线程的第十次迭代中被调用,工作线程可能不会处理在退出调用之前收到的所有消息(我们得到值 3
作为 worker 处理的最后一个值)。*
实际上,Qt 提供了一种规范的方法来退出工作线程并执行必要的清理,因为信号 QThread::finished
是在 special way 中处理的。 :
When this signal is emitted, the event loop has already stopped running. No more events will be processed in the thread, except for deferred deletion events. This signal can be connected to QObject::deleteLater(), to free objects in that thread.
这意味着你可以使用thread->quit()
(和你做的一样),但你只需要添加:
connect(my_thread, &QThread::finished, my_threaded_class, &ThreadClass::stop);
到您的 startThread
并从析构函数中删除不必要的 emit stopThread();
。
* 我在文档中找不到任何详细解释此行为的页面,因此我提供了这个最小示例来解释我在说什么。
关于c++ - Programm parallel QThread 在应用程序退出时创建内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53468408/
IntentReceiver 正在泄漏 由于 onDetachedFromWindow 在某些情况下未被调用。 @Override protected void onDetachedFromWind
好吧,我很难追踪这个内存泄漏。运行此脚本时,我没有看到任何内存泄漏,但我的 objectalloc 正在攀升。 Instruments 指向 CGBitmapContextCreateImage >
我编写了一个测试代码来检查如何使用 Instrument(Leaks)。我创建了一个单一 View 应用程序,单击按钮后我加载了一个像这样的新 View ... - (IBAction)btn_clk
我正在使用这个简单的代码并观察单调增加的内存使用量。我正在使用这个小模块将内容转储到磁盘。我观察到它发生在 unicode 字符串上而不是整数上,我做错了什么吗? 当我这样做时: >>> from u
我有以下泄漏的代码。 Instruments 表示,泄漏的是 rssParser 对象。我“刷新”了 XML 提要,它运行了该 block 并且发生了泄漏...... 文件.h @interface
我在我编写的以下代码片段中发现了内存泄漏 NSFileManager *fileManager=[[NSFileManager alloc] init]; fileList=[[fileManager
因此,我正在开发HTML5 / javascript rts游戏。观察一直有几种声音在播放。因此,对我来说,是一段时间后声音听起来像是“崩溃”,并且此浏览器选项卡上的所有声音都停止了工作。我只能通过重
下面是我正在使用的一段代码及其输出。 my $handle; my $enterCount = Devel::Leak::NoteSV($handle); print "$date entry $en
在这篇关于 go-routines 泄漏的帖子之后,https://www.ardanlabs.com/blog/2018/11/goroutine-leaks-the-forgotten-sende
我想知道为什么在执行 ./a.out 后随机得到以下结果。有什么想法我做错了吗?谢谢 http://img710.imageshack.us/img710/8708/trasht.png 最佳答案 正
我正在 Swift 中开发一个应用程序,在呈现捕获我放在一起的二维码的自定义 ViewController 后,我注意到出现了巨大的内存跳跃。 该代码本质上基于以下示例:http://www.appc
下面是我的 javascript 代码片段。它没有按预期运行,请帮我解决这个问题。 function getCurrentLocation() { console.log("insi
我们在生产环境中部署了 3 个代理 Kafka 0.10.1.0。有些应用程序嵌入了 Kafka Producer,它们将应用程序日志发送到某个主题。该主题有 10 个分区,复制因子为 3。 我们观察
我正在使用仪器来检测一些泄漏,但有一些泄漏我无法解决; NSMutableString *textedetails = [[NSMutableString alloc] init];
如果我使用性能工具测试我的代码 - 泄漏,它没有检测到任何泄漏。这是否意味着代码没有泄漏任何内存? 我有一个越狱的 iPhone,我可以监控可用内存。如果有人知道,那就是 SBSettings。我测试
我在从 AddressBook 中获取图像时遇到了很大的问题,下面我粘贴了我的代码。此 imageData 从未被释放,在我的 Allocations Instruments 上它看起来总是在内存中它
- (NSMutableArray *)getArrayValue:(NSArray *)array{ NSMutableArray *valueArray = [NSMutableArra
Instruments 工具说这是一个泄漏,有什么想法吗? 我在 for 循环结束时释放变量对象 在上述方法的开头,这就是我设置变量对象的方式,即自动释放; NSMutableArray *varia
我正在跟踪我的 iOS 应用程序的内存泄漏,我有一个奇怪的泄漏导致我的应用程序崩溃......负责的框架是:CGImageMergeXMPPropsWhithLegacyProps。在某些时候,我的应
我正在尝试使用 NSOperationQueue 在后台线程中执行一个方法,如下所示: NSOperationQueue *queue = [NSOperationQueue new]; NS
我是一名优秀的程序员,十分优秀!