Qt中postevent造成内存泄漏问题的通用解决方案

这篇具有很好参考价值的文章主要介绍了Qt中postevent造成内存泄漏问题的通用解决方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在Qt中由QCoreApplication统一管理Qt事件的收发和销毁,其中sendEvent为阻塞式发送,用于单线程的事件发送;postevent为非阻塞式发送,构造事件的线程和接受事件的线程可以为两个线程。

最近在做一个个人项目ShaderLab

Qt中postevent造成内存泄漏问题的通用解决方案,QT,qt,踩坑,Qt事件

需要绘制OpenGL实时渲染的图像,由于OpenGL渲染基本都放在循环语句内,直接放在主线程会导致界面卡死不响应,所以考虑另开一个线程在后台渲染,再把渲染好的图像在循环语句内通过postevent发送给前端的Widget

Qt中postevent造成内存泄漏问题的通用解决方案,QT,qt,踩坑,Qt事件

 因此要想QCoreApplication注册一个QEvent类型,通过该类型的成员变量保存Image数据

//EvSendFrame.h

#include <QEvent>

class EvSendFrame : public QEvent
{
public: 
	EvSendFrame(void* frameData,int size);
	~EvSendFrame();
	static Type eventType;

public:
	uchar* _framedata;
};

#endif
//EvSendFrame.cpp

#include "EvSendFrame.h"

QEvent::Type EvSendFrame::eventType = (QEvent::Type)QEvent::registerEventType(QEvent::User + 1);

EvSendFrame::EvSendFrame(void* frameData,int size):QEvent(Type(eventType))
{
	_framedata = (uchar*)malloc(size);
	memcpy(_framedata, frameData, size);
}

在OpenGL绘制循环内每更新一次window缓冲区就发送给前端Widget一张图片

	while (tmp = !paused.load(memory_order_acquire))
	{
		auto time = static_cast<float>(glfwGetTime());
		deltaTime = time - lastTime;
		lastTime = time;
		glUniform1f(glGetUniformLocation(_shader->ID, "runtime_data.iTime"), time);
		renderQuad();
		
		switch (_type)
		{
			case XA_GL_RGB:
				glReadPixels(0, 0, SCR_WIDTH, SCR_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, _windowbuf);
				break;
			case XA_GL_RGBA:
				glReadPixels(0, 0, SCR_WIDTH, SCR_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, _windowbuf);
				break;
			default:
				break;
		}
		flip(&((uint8_t*)_windowbuf));

		auto event = new EvSendFrame(_windowbuf,windowBufSize);
		QApplication::postEvent(_reciver, event, Qt::HighEventPriority);

		glfwSwapBuffers(_window);
		glfwSwapInterval(1);
		glfwPollEvents();
	}

在前端Widget中重载EventFilter虚函数以处理该Event

bool GLWidget::eventFilter(QObject* obj, QEvent* event)
{
	if (event->type() == EvSendFrame::eventType)
	{
		EvSendFrame* ev = (EvSendFrame*)event;
		_picture = QImage(event->_framedata, SCR_WIDTH, SCR_HEIGHT, QImage::Format_RGB888);
		this->repaint();
	}

	return QWidget::eventFilter(obj, event);
}

结果是内存泄漏非常严重,QEvent不会自动释放,以一秒60帧来算,粗略估计就是一秒造成60张600x800图片大小的内存泄漏,非常恐怖!

Qt中postevent造成内存泄漏问题的通用解决方案,QT,qt,踩坑,Qt事件

 可以看到程序的使用内存很快从900M干到了1700多M!对于一个应用程序来说显然是不可接受的。

知道了大概是哪个地方出现内存泄漏后,就可以开始着手修改代码了。按照Stackflow老哥的说法应该将QEvent用智能指针包裹。

Qt中postevent造成内存泄漏问题的通用解决方案,QT,qt,踩坑,Qt事件

auto event = std::make_unique<EvSendFrame>(_windowbuf, windowBufSize);
QApplication::postEvent(_reciver, event.release(), Qt::HighEventPriority);

修改event的构造后发现还是和前面的情况一样,问题出现在哪里?哦,没有定义自定义Event的析构函数

EvSendFrame::EvSendFrame(void* frameData,int size):QEvent(Type(eventType))
{
	_framedata = (uchar*)malloc(size);
	memcpy(_framedata, frameData, size);
}

EvSendFrame::~EvSendFrame()
{
	free(_framedata);
}

这里就要注意一点了,如果你自定义的QEvent类在构造的时候从堆内申请内存,一定要定义该Event的析构函数释放从堆内申请的内存!!!

添加析构函数后运行会崩溃?在前端Widget类中预分配一块同样大小的内存,每次Event销毁前先拷贝需要缓存的数据。

static GLWidget::_glwgt_pctbuffing = (uchar*)malloc(SCR_WIDTH * SCR_HEIGHT * 3 * sizeof(uchar));
static GLWidget::_glwgt_buffingsize = SCR_WIDTH * SCR_HEIGHT * 3 * sizeof(uchar);


bool GLWidget::eventFilter(QObject* obj, QEvent* event)
{
	if (event->type() == EvSendFrame::eventType)
	{
		EvSendFrame* ev = (EvSendFrame*)event;
        memcpy(_glwgt_pctbuffing,ev->_framedata, GLWidget::_glwgt_buffingsize);//copy to unique memory to avoid memory leak
		_picture = QImage(event->_framedata, SCR_WIDTH, SCR_HEIGHT, QImage::Format_RGB888);
		this->repaint();
	}

	return QWidget::eventFilter(obj, event);
}

可以看到在free了_framedata后程序的内存使用情况非常稳定,只有50几M

Qt中postevent造成内存泄漏问题的通用解决方案,QT,qt,踩坑,Qt事件文章来源地址https://www.toymoban.com/news/detail-617617.html

到了这里,关于Qt中postevent造成内存泄漏问题的通用解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Handler内存泄漏原因及解决方案

    在Activity中,将Handler声明成非静态内部类或匿名内部类,这样Handle默认持有外部类Activity的引用。如果Activity在销毁时,Handler还有未执行完或者正在执行的Message,而Handler又持有Activity的引用,导致GC无法回收Activity,导致内存泄漏。如以下两种情形可能导致内存泄漏 1、在Act

    2024年02月16日
    浏览(60)
  • Android 内存泄漏的常见原因及其对应的解决方案

    Android应用程序中常见的内存泄漏原因有很多,以下是一些常见的原因及对应的解决方案: 1. 静态引用导致的内存泄漏: 静态变量持有对Activity或Fragment的引用,导致它们无法被垃圾回收机制释放。 解决方案: 确保不将Activity或Fragment的实例赋值给静态变量。如果确实需要使用

    2024年02月08日
    浏览(53)
  • Java中关于内存泄漏分析和解决方案,都在这里了!

    最近正在熟悉Java内存泄漏的相关知识,上网查阅了一些资料,在此做个整理算是对收获的一些总结,希望能对各位有所帮助,有问题可以文末留言探讨、补充。 如下是整篇文章的结构,所需阅读时间大约20min 内存泄漏 :对象已经没有被应用程序使用,但是垃圾回收器没办法

    2024年02月13日
    浏览(43)
  • torch.empty()造成的内存溢出问题

    代码实现的时候遇见了一个很奇怪的问题,运行同一段代码会出现一些奇怪的超大指数值,调试发现是混淆了torch.empty 和torch.zeros的概念。对torch.empty初始化的矩阵直接“+=”,出现的内存问题。 例如: 上述代码不会报错,但是结果不正确。 这是由于torch.empty 创建了矩阵会分

    2024年01月24日
    浏览(35)
  • 内存泄漏问题

            内存泄漏是一种常见的问题,它可能导致系统内存不断增加,最终耗尽可用内存。解决内存泄漏问题通常需要进行调试和分析。下面是一些可能有助于解决内存泄漏问题的步骤: 1. 监控内存使用情况: a. 使用 malloc 记录日志: 在内存分配的地方添加记录,以便跟

    2024年01月17日
    浏览(44)
  • ThreadLocal有内存泄漏问题吗

    对于ThreadLocal的原理不了解或者连Java中的引用类型都不了解的可以看一下我的之前的一篇文章Java中的引用和ThreadLocal_鱼跃鹰飞的博客-CSDN博客 我这里也简单总结一下: 1. 每个Thread里都存储着一个成员变量,ThreadLocalMap 2. ThreadLocal本身不存储数据,像是一个工具类,基于ThreadL

    2024年02月14日
    浏览(46)
  • ClickHouse中“大列”造成的JOIN的内存超限问题

    “大列”是指单行数据量非常大的列,通常是100KiB以上。这样的列会导致JOIN(通常LEFT JOIN 和 INNER JOIN)出现内存超限的异常。 这里讨论的是常用的JOIN算法:partial merge join 与 hash join。Direct join算法不在本文讨论范围。 内存超限的错误一般长这样: 为了分析“大列”的JOIN运算

    2024年01月22日
    浏览(39)
  • C++ map clear内存泄漏问题

    map自带的clear()函数会清空map里存储的所有内容,但如果map值存储的是指针,则里面的值不会被清空,会造成内存泄漏,所以值为指针的map必须用迭代器清空。 使用erase迭代删除 迭代器删除值为指针的map,一定要注意迭代器使用正确,一旦迭代器失效程序就会崩溃。 调用cle

    2024年02月09日
    浏览(37)
  • 使用asan检测内存泄漏、堆栈溢出等问题

    操作过程参考:链接 缘起:程序在移动端崩溃,mac端复现不了,于是在写个崩溃位置函数的调用demo,使用ASAN工具进行排查。 验证过程 1、代码 main.cpp 使用附加ASAN工具的方式进行编译: 执行: 没有问题,以上是验证过程,如有问题执行时ASAN会提示有问题的相关位置。 介绍

    2024年02月11日
    浏览(63)
  • 【Go】常见的四个内存泄漏问题

    1、这里更多的是由于channel+for+select导致的,错误的写法导致了发送者或接收者没有发现channel已经关闭,任务已经结束了,却仍然在尝试输入输出https://geektutu.com/post/hpg-exit-goroutine.html 不要把map用作全局

    2024年02月13日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包