2014-10-31 22 views
13

我已经自己解决了这个问题,奖励不会被授予。这个问题是由非GUI线程启动的GUI操作引起的。Qt 4.7:TCP线程,数据传输导致内存泄漏

的Qt 4.7 OSX 10.6.8

有一个在应用了大量的代码,但不参与什么事情一大堆。

数据内存泄漏发生在单个连接的上下文中,该连接在单个Qt线程中打开,读取,写入和关闭。我使用一个固定的存储器对象(PMSG),以保持我的消息,然后将它们发送到所述外部设备是这样的:

m_pTcpSocket->write((char*)pMsg->Buf8, (qint64)pMsg->GetLength()); 

BUF8是一个2048字节的静态阵列。 GetLength是消息的前16位,与0xFF对应,因此0到255之间的数字应该返回4,这些消息总是在我的诊断中出现。这两个操作都由自己的互斥体(意思是不同的互斥体)包围。消息长度通常为4个字节。这些消息可靠地到达我们有线局域网中其他地方的接收设备;它们在到达时是正确的,并且设备只针对这些消息进行适当的ACK响应。之后我尝试添加一个调用flush()的方法;没有帮助(也不应该有任何冲洗,但...)我不知道泄漏是在写()。

发送这些消息反过来导致我收到来自设备的ACK消息。我读它是这样的:(当然)

if (m_pTcpSocket->waitForReadyRead(100)) 
{ 
    while ((bytesavailable = m_pTcpSocket->bytesAvailable())) 
    { 
     m_pTcpSocket->read(RBuf, bytesavailable); 
     AssembleMsg(Buf, bytesavailable); // state machine empties Buf 
    } 
} 

循环后,信息bytesAvailable为零BUF是一个无符号字符指针2048无符号字符的静态阵列在其被接收的数据的各部分之后,我运行一个组装消息的简单状态机。消息长度为4.消息按预期接收和汇编,不进行内存分配,也不声明对象。这两个操作都被自己的互斥体所包围(意思是不同的互斥体,所以它们不能在rx和tx之间进行交互)。一旦消息汇编完成,它所做的就是重置一个计数器,将计时器设置为下一个保持消息的延迟如果没有它们,设备将断开连接。)通过在waitforreadyread(100)之后进行计数来累积延迟,只要设备不向该端口发送任何内容(这是典型行为),该延迟就会计算该长度的间隔。这样就不需要定时器。计时工作正常。只要消息到达,或者至少在100毫秒内读取消息。他们不累积。所以我认为读取缓冲区不会变大(呃)。但是......我不知道。东西越来越大!

这就是阅读。但是我不知道泄漏是否在read()中。

但它必须是一个或另一个。如果我不发送这些消息(这意味着我也没有收到ACK消息),那么就没有泄漏。应用程序中任何地方都没有其他更改这是它启动的模式,没有其他活动正在进行,我只是保持连接打开,所以当它运行收音机的时候,端口就准备好了。

这两个都在同一个线程中运行,并且它们都运行在同一个套接字上。线程持续运行,并且相同的套接字保持打开(实际上几个小时)。所以它不是套接字对象删除问题。

由于某些品牌的SDR收音机需要在接收操作期间保持活动状态,这意味着该应用程序坐在那里,并且在接收到时像坐在那里等待时一样疯狂地咀嚼内存。

我在大约12小时内损失了大约250兆字节,大概在100k以下。我可以一次观看应用程序内存增加1MB,大约每秒一次。

我已经搜索了很多,我能找到的所有讨论都没有通过多个连接删除tcp对象,这在这里绝对不是问题。

我真的很茫然。问题与我在线程中使用套接字有关吗?应用程序(一个非常复杂的软件定义无线电应用程序)可以运行10到16个线程,具体取决于它在做什么;我在自己的线程中运行数据传输,因此它们不会受到与主事件循环相关的任何事情的影响。

我试过valgrind,但它试图启动它之前终止了应用程序,在这之前就开始了。我不认为它喜欢线程或其他东西。或者它可能是10.6.8,但无论如何,这是行不通的。无论如何,Qt 4.7并没有整合它。我知道没有办法跟踪应用程序中的内存使用情况,这样我就可以包装每个发送和接收,并至少弄清楚哪一个(或两者?)负责。

***编辑:通过改变keepalive消息的速率,我直接改变了内存泄漏的速度,正如我上面所说的,如果keepalive没有被发送,所有。

这就是我所能想到的告诉你的人;任何建议都欢迎,任何有关Qt中的TCP怪癖的照明都会受到欢迎,基本上都是如此。我已经花了很多时间在这个问题上,并且在这个关头我只是受到了限制。

+1

你写了很多按键,似乎表明你可以产生一个很好的短[MCVE](http://stackoverflow.com/help/mcve)来消除所有的疑问,但是你是否真的试过在单线程[MCVE](http://stackoverflow.com/help/mcve)? – Sebivor 2015-12-30 04:15:01

+1

我看到五个函数调用,我们没有代码(4用'm_pTcpSocket'和'AssembleMsg')。其中任何一个都可能是罪魁祸首。你可以添加这些代码吗? – 1201ProgramAlarm 2015-12-30 04:40:20

+0

人们,这个问题并没有在一个简短的例子中重现。这可能是我在这之外做的事情;但我们正在谈论大量的代码行 - 该应用程序大约有55k行代码,不包括Qt生成的任何内容。而且有很多来回TCP和传入的UDP。如果这里不太明显,其他地方就不那么明显了。它当然可以在其他地方 - 我认为我做对了,我只是没有想法。我觉得提供赏金有点不好,我想我可能会浪费人们的时间。但我没有办法撤回它。 – fyngyrz 2015-12-30 06:39:00

回答

7

我找到了。从非gui线程绘制以非常间接的方式打破Qt。停止这样做,它停止泄漏。感谢大家。

这是@Shf值得信贷,但可悲的是,我真的不明白赏金很好,我可能告诉他在这里得到并回答为时已晚。当他得到我的信息时,我会通过为他提供关键暗示的问题提供赏金来弥补他。赏金将包括我的堆栈溢出代表的其余部分,包括这个问题所获得的收益。我现在可以做的最好的;下次我会更清楚。这绝对是教育。

+0

与Qt中的用户界面进行通信只能通过信号和插槽来保护您免受多线程错误的影响。 另外Qt newtworp部件的设计方式不需要穿线。 – 2016-01-04 09:03:26

+0

我很高兴将赏金通过@shf。我想如果他发布了一个答案,我可以开始奖励并奖励它。但我没有看到任何答案...? SO赏金制度确实是一个雷区! – Roddy 2016-01-07 10:12:05

+0

你真是太好了。他没有回到我身边 - 我为他留下了几个指针。也许是新年的假期。 :) – fyngyrz 2016-01-07 16:17:34

3

可以发现线性影响泄漏率的重要线索。你提到keepalive消息就是这样一种东西,我认为这些消息是由应用程序发送的,没有收到。

从发送方来看,您将展示如何发送单条消息,而不是如何管理发出消息的队列。因此,我的建议是检查发送后是否正确删除了消息,或者在管理该数据结构时是否存在其他问题。

5

不是真的够在代码方面上工作,但我想看看这些东西: -

  • 你怎么知道你有内存泄漏?
  • 你怎么知道它实际上并不是堆腐败
  • 在任何地方都没有“新”或“删除”。如果你不使用它们,那么'泄漏'可能在TCP处理中。
  • 套接字:尝试关闭并重新打开每隔一段时间。当你这样做时,泄漏是否得到清理?
  • 您读入RBuf,然后从Buf汇编...?
  • 什么类型是RBuf?为什么没有边界检查你读入的数量?
  • Wireshark - 查看您的套接字上发送/接收的内容 - 发生什么异常。或者,任何去其他套接字的东西。
  • 你实际上是从套接字读取字节吗?检查返回值read,并参见this question
2

您显示和描述的代码似乎没有泄漏。

由于Valgrind不起作用,所以下一个最好的做法是尝试LeakSanitizer(http://clang.llvm.org/docs/LeakSanitizer.html)和/或AddressSanitizer(http://clang.llvm.org/docs/AddressSanitizer.html)。地狱,运行你可以的所有消毒剂,也许会出现一些东西。

除此之外,我从代码中得到的唯一线索是处理pMsg:它是如何分配和释放的?我们没有看到代码。检查它或分享它,如果你愿意。

1

没有必要使用多线程。 结帐my other answer。它完美地匹配您的问题,并会终止您的多线程问题。

也在Qt中总是使用信号和插槽。默认情况下,它们保护代码不受交叉线程问题的影响,并具有更多优点

+0

线程在这里是必需的,因为否则太多的事情会被打包到GUI线程中,并且应用程序无法成功运行。无论如何,它不是TCP线程,无论如何都是在做GUI操作。所以谢谢,但不是谢谢。正如我所说,问题已经解决了。 – fyngyrz 2016-01-05 16:46:10

+0

你是完全错误的。你的应用程序设计简单地被破坏了。阻塞线程总是一个不好的解决方案。另外在Qt中,线程之间的通信应该通过使用信号和插槽来执行,这会简化很多并且安全。 [Here you have](http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/)关于多线程的一些提示。 – 2016-01-06 10:15:11

+0

谁说我阻止了一个线程?你*非常*困惑。 – fyngyrz 2016-01-07 01:47:19