Qt 4.7:TCP线程,数据传输导致内存泄漏 [英] Qt 4.7: TCP thread, data transfer causes memory leak

查看:2523
本文介绍了Qt 4.7:TCP线程,数据传输导致内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我自己解决了这个问题,赏金不会被授予。

Qt 4.7
OSX 10.6.8的问题是由于非GUI线程启动的GUI操作的结果而产生的。

Qt 4.7 OSX 10.6.8

应用程序中有很多代码,但并不涉及到发生了什么。

There's a lot of code in the app, but not a whole lot involved with what's going on.

数据内存泄漏发生在单个连接的上下文中,单个连接在单个Qt线程中打开,读取,写入和关闭。我使用固定内存对象(pMsg)来保存我的邮件,然后将它们发送到外部设备,如下所示:

The data memory leak occurs in the context of a single connection, which is opened, read, written and closed within a single Qt thread. I'm using a fixed memory object (pMsg) to hold my messages, then sending them to the external device like this:

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

Buf8是一个2048字节的静态数组。 GetLength是消息的前16位,并对0xFF,所以一个从0到255的数字。应该返回4为这些消息,总是在我的诊断。这两个操作都由它们自己的互斥体(意思是,不同的互斥体)包围。消息长度通常为4字节。消息可靠地到达我们有线LAN上的其他地方的接收设备;它们在它们到达时是正确的,并且设备适当地响应于仅特定于那些消息的ACK。我试过添加一个对flush()调用;没有帮助(也不应该有任何东西冲洗,但...)我不知道泄漏是在write()。

Buf8 is a 2048 byte static array. GetLength is the first 16 bits of the message and'ed against 0xFF, so a number from 0 to 255. Should return 4 for these messages, always has in my diagnostics. Both operations are surrounded by their own mutexes (meaning, different mutexes.)The message lengths are typically 4 bytes. The messages dependably get to the receiving device elsewhere on our wired LAN; they're correct when they arrive and the device responds appropriately with an ACK specific to only those messages. I've tried adding a call to flush() afterwards; doesn't help (nor should there be anything to flush, but...) I don't know that the leak is in the write().

发送这些消息又导致我从设备接收ACK消息。我读这样:

Sending these messages in turn causes me to receive an ACK message from the device. I read it like this:

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

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

After the loop, bytesavailable is zero (of course.) Buf is an unsigned char pointer to 2048 static array of unsigned chars upon which, after each portion of data is received, I run a simple state machine that assembles the messages. Message lengths are 4. Messages are received and assembled as expected, no memory allocations are made, nor objects declared. Both operations are surrounded by their own mutexes (meaning, different mutexes so they can't interact between rx and tx.) Once the message is assembled, all it does is reset a counter that sets the delay to the next keepalive message (which is what these are. without them, the device will drop the connection.) The delay is accumulated by counting after the waitforreadyread(100), which counts intervals of that length as long as the device sends nothing to this port, which is typical behavior. In this way, no timer is required. The timing works fine. Messages are read as soon as they arrive, or at least, within 100 ms. They don't accumulate. So I thought the read buffer would not get larg(er). But... I don't know. Something is getting larger!

这是阅读。但我不知道泄漏是在read(),或者。

So that's the read. But I don't know that the leak is in the read(), either.

但它已经是一个或另一个。如果我不发送这些消息(这意味着我没有得到ACK消息,),那么没有泄漏。在应用程序中的任何地方都没有其他变化。这是它启动的模式,没有其他活动,我只是保持连接打开所以当它的时间运行收音机,港口准备去。

BUT it HAS to be one or the other. If I don't send these messages (which means I don't get the ACK messages, either), then there is no leak. Nothing else changes anywhere in the application. This is the mode it powers up in, and no other activity is going on, I'm just keeping the connection open so when it's time to run the radio, the port is ready to go.

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

Both of these run in the same thread, and they both run off of the same socket. The thread runs continuously, and the same socket remains open (for hours, in fact.) So it's not a socket object delete issue.

某些品牌的问题更加严重的SDR无线电,因为它们需要在接收操作期间的保持活动,这意味着应用程序坐在那里,当接收时像疯狂的,当它坐在那里只是等待去时,嚼了记忆。

The problem is exacerbated with certain brands of SDR radios, as they require the keepalive during receive operation, which means the app sits there and chews up memory like crazy when receiving as WELL as when it is sitting there just waiting to go.

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

I'm losing about 250 megabytes in approximately 12 hours, in chunks somewhere under 100k. I can watch the app memory increase.1 mb at a time, about once a second.

我已经广泛搜索,我可以找到谈论的是无法删除tcp对象通过多个连接,这绝对不是这里的问题。

I have googled extensively, and all I can find talks about is failing to delete the tcp object over multiple connections, which is definitely not the issue here.

我真的在亏本。这个问题是否与我在线程中使用套接字有关?应用程序(一个非常复杂的软件定义的无线电应用程序)运行在10到16线程之间,取决于它在做什么;我在自己的线程中运行数据传输,所以它们不会被任何绑定主要事件循环的东西所破坏。

I'm really at a loss. Is the problem related to my use of the socket in a thread? The application (a very complex software defined radio app) runs anywhere from 10 to 16 threads, depending on what it's doing; I run the data transfers in their own thread so they aren't compromised by anything that ties up the main event loop.

我试过valgrind,但它终止应用程序后,它试图启动它,在任何这一切都走之前。我不认为它喜欢线程,或者什么。或者也许是10.6.8,但无论如何,它不工作。 Qt 4.7不集成它。我知道没有办法跟踪内存使用从应用程序内,使我可以包装每个发送和接收,并至少弄清哪一个(或两个?)负责。

I've tried valgrind, but it terminates the app a bit after it tries to start it, well before any of this gets going. I don't think it likes threading, or something. Or maybe it's 10.6.8, but anyway, it doesn't work. Qt 4.7 doesn't integrate it anyway. I know of no way to track memory use from within the application so that I could wrap each send and receive and at least figure out which one (or both?) is responsible.

*** edit:通过改变keepalive消息的速率,我直接改变内存泄漏的速率,正如我上面所说的,如果keepalive没有被发送,根本没有内存损失。

*** edit: By changing the rate of the keepalive message, I directly change the rate of the memory leak, and as I think I said above, if the keepalive isn't being sent, there's no memory loss at all.

这是我能想到的告诉你们的人;欢迎任何建议,任何关于TCP奇怪的Qt的照明将欢迎,基本上任何东西。我已经花了很多天,在这个时候,我只是stonewalled。

That's all I can think of to tell you folks; any suggestions are welcome, any illumination about TCP quirks in Qt would be welcome, basically anything. I've spent many days on this and I'm just stonewalled at this juncture.

推荐答案

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

I found it. Drawing from a non-gui thread was breaking Qt in a very indirect way. Stopped doing that, and it stopped leaking. Thanks everyone.

这是@Shf应得的信用,但可惜的是,我真的不明白这样的赏金,我可能告诉他来到这里,回答太晚了。当他收到我的信息时,我会在他提供关键提示的问题上提供一个赏金。赏金将包括我的堆栈溢出rep的其余部分,包括这个问题所赚的。最好我现在可以做;我下次会更好。这绝对是教育性的。

It is @Shf who deserves the credit, but sadly, I didn't really understand bounties that well and I probably told him to get in here and answer too late. I will make it up to him -- when he gets my message -- by offering a bounty on the question where he actually provided the critical hint. The bounty will consist of the rest of my stack overflow rep, including what's been earned by this question. Best I can do for now; I'll know better next time. It's definitely been educational.

这篇关于Qt 4.7:TCP线程,数据传输导致内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆