Results 1 to 5 of 5

Thread: QTcpSocket - memory allocation problem

  1. #1
    Join Date
    Jul 2011
    Posts
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    1

    Default QTcpSocket - memory allocation problem

    Hi All,

    I have a problem with Qt's sockets. I have a server application that listens for incoming connections and a client application that connects to the host. So far so good. I'm able to create the connection and send/receive data. The client sends a huge amount of data (in blocks) to the server, while keeping up the connection.

    I encountered a problem that drives me crazy since a few days now, and I haven't found any solution yet. I tried to narrow down the problem to minimum and to have an example code for showing.

    At some point there is a memory issue, but I can't figure out what causes it:
    std::bad_alloc at memory location 0x0019d434

    Here is the code example

    Server Application:

    TcpServer
    Qt Code:
    1. #ifndef TCPSERVER_H
    2. #define TCPSERVER_H
    3.  
    4. #include "serversocket.h"
    5.  
    6. #include <QTcpServer>
    7. #include <QHostAddress>
    8.  
    9. class TcpServer : public QTcpServer
    10. {
    11. Q_OBJECT
    12. public:
    13. TcpServer ( QObject * parent = 0 ) : QTcpServer(parent)
    14. {
    15. if (!this->listen( QHostAddress::LocalHost, 2688))
    16. {
    17. exit(-1);
    18. }
    19. };
    20.  
    21. protected:
    22. virtual void incomingConnection ( int socketDescriptor )
    23. {
    24. ServerSocket *socket = new ServerSocket(this);
    25. socket->setSocketDescriptor(socketDescriptor);
    26. connect(socket, SIGNAL(readyRead()), socket, SLOT(readBlockData()));
    27. };
    28.  
    29. };
    30.  
    31. #endif // TCPSERVER_H
    To copy to clipboard, switch view to plain text mode 

    ServerSocket
    Qt Code:
    1. #ifndef SERVERSOCKET_H
    2. #define SERVERSOCKET_H
    3.  
    4. #include <QTcpSocket>
    5. #include <QHostAddress>
    6. #include <QDataStream>
    7.  
    8. #include <iostream>
    9. #include <cstring>
    10.  
    11. class ServerSocket : public QTcpSocket
    12. {
    13. Q_OBJECT
    14. public:
    15. ServerSocket ( QObject * parent = 0 ) : QTcpSocket(parent)
    16. {
    17. this->blockSize = 0;
    18. };
    19.  
    20. public slots:
    21. void readBlockData()
    22. {
    23. QDataStream in(this);
    24. in.setVersion(QDataStream::Qt_4_7);
    25.  
    26. if (this->blockSize == 0)
    27. {
    28. if (this->bytesAvailable() < (int)sizeof(quint32))
    29. return;
    30.  
    31. in >> this->blockSize;
    32. }
    33.  
    34. if (this->bytesAvailable() < this->blockSize)
    35. return;
    36.  
    37. char* blockData = new char[this->blockSize];
    38. in >> blockData;
    39.  
    40. QByteArray byteArray(blockData);
    41.  
    42. std::cout << (int)byteArray.size() << " - " << this->bytesAvailable() << "\n";
    43.  
    44. this->blockSize = 0;
    45.  
    46. delete[] blockData;
    47. };
    48.  
    49. private:
    50. quint32 blockSize;
    51.  
    52.  
    53. };
    54.  
    55. #endif // SERVERSOCKET_H
    To copy to clipboard, switch view to plain text mode 

    Main
    Qt Code:
    1. #include <QtCore/QCoreApplication>
    2.  
    3. #include "tcpserver.h"
    4.  
    5. int main(int argc, char *argv[])
    6. {
    7. QCoreApplication a(argc, argv);
    8.  
    9. TcpServer *server = new TcpServer();
    10.  
    11. return a.exec();
    12. }
    To copy to clipboard, switch view to plain text mode 

    Client application:

    ClientSocket
    Qt Code:
    1. #ifndef CLIENTSOCKET_H
    2. #define CLIENTSOCKET_H
    3.  
    4. #include <QTcpSocket>
    5. #include <QHostAddress>
    6. #include <QDataStream>
    7.  
    8. #include <iostream>
    9. #include <cstring>
    10.  
    11. class ClientSocket : public QTcpSocket
    12. {
    13. Q_OBJECT
    14. public:
    15. ClientSocket ( QObject * parent = 0 ) : QTcpSocket(parent)
    16. {
    17. connectToHost(QHostAddress::LocalHost, 2688);
    18. if (!this->waitForConnected(3000))
    19. exit(-1);
    20. };
    21.  
    22. void writeBlockData(const char* blockData, size_t size)
    23. {
    24.  
    25. QByteArray dataArray((char*) blockData, size);
    26.  
    27. QByteArray block;
    28. QDataStream out(&block, QIODevice::WriteOnly);
    29. out.setVersion(QDataStream::Qt_4_7);
    30.  
    31. out << (quint32)0;
    32. out << dataArray;
    33. out.device()->seek(0);
    34. out << (quint32)(block.size() - sizeof(quint32));
    35.  
    36. this->write(block);
    37. this->flush();
    38.  
    39. this->waitForBytesWritten(-1);
    40. };
    41. };
    42.  
    43. #endif // CLIENTSOCKET_H
    To copy to clipboard, switch view to plain text mode 

    Main
    Qt Code:
    1. #include <QtCore/QCoreApplication>
    2.  
    3. #include "clientsocket.h"
    4.  
    5. int main(int argc, char *argv[])
    6. {
    7. QCoreApplication a(argc, argv);
    8.  
    9. unsigned int size = 1000*1000*3;
    10. char *data = new char[size];
    11.  
    12. for (int i = 0; i < size; i++)
    13. {
    14. data[i] = 'q';
    15. }
    16.  
    17. ClientSocket client;
    18.  
    19. for (int blocks = 0; blocks < 2000; blocks++)
    20. {
    21. client.writeBlockData(data, size);
    22. std::cout << blocks << std::endl;
    23. }
    24.  
    25. delete[] data;
    26.  
    27. return a.exec();
    28. }
    To copy to clipboard, switch view to plain text mode 

    I was testing the code on Windows 7 with Qt 4.7 using visual studio 2008.

    1.
    The first problem is not really a problem, but more something that I found worth mentioning and I was wondering if someone else experienced something similar.
    When running the code in Debug mode after reading data from the socket server, the buffer seems not to be cleared. The memory keeps increasing until there is nothing left to be allocated. This seems not to be the case for compiling and running the code in Release mode.

    2.
    But weird is, that even in Release mode, after the same number of received blocks, I get the above mentioned exception and the server application crashes.


    Thank you!!!
    Last edited by dreac; 30th July 2011 at 23:45.

  2. #2
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanked 268 Times in 268 Posts
    Wiki edits
    20

    Default Re: QTcpSocket - memory allocation problem

    Quote Originally Posted by dreac View Post
    Qt Code:
    1. virtual void incomingConnection ( int socketDescriptor )
    2. {
    3. ServerSocket *socket = new ServerSocket(this);
    4. socket->setSocketDescriptor(socketDescriptor);
    5. connect(socket, SIGNAL(readyRead()), socket, SLOT(readBlockData()));
    6. };
    To copy to clipboard, switch view to plain text mode 
    The memory keeps increasing until there is nothing left to be allocated. This seems not to be the case for compiling and running the code in Release mode.
    Try to understand the piece of code I quoted above to see if you can spot the huge memory leak.
    You are getting out of memory. In debug mode a lot faster than in release mode of course.

  3. #3
    Join Date
    Jul 2011
    Posts
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    1

    Default Re: QTcpSocket - memory allocation problem

    Thanks, but ... sorry, I don't get it. I can't see anything wrong with this. Could you please point out what's causing a memory leak here?

    This is executed every time a client calls connectToHost(). Thus if only 1 client connects, then I will get only 1 instance of serversocket. The socket descriptor is passed to the tcp socket who then emits the signal readyRead() whenever data is coming in. The signal is connected to my method readBlockData() which reads the data from the stream, and thus should free the buffer.

    I set a breakpoint at these lines to check how often a ServerSocket is instantiated, and it was only once as expected.

    Or did I miss anything else here.

  4. #4
    Join Date
    Jan 2006
    Location
    Belgium
    Posts
    1,938
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanked 268 Times in 268 Posts
    Wiki edits
    20

    Default Re: QTcpSocket - memory allocation problem

    Qt Code:
    1. ServerSocket *socket = new ServerSocket(this);
    To copy to clipboard, switch view to plain text mode 
    This creates a local variable called socket which points to a memory location.

    Two important facts:
    1. local means that the variable will be deleted at the end of the scope, in this case the } bracket of the function.
    2. Since it is a pointer, the memory allocated will not be freed at the end of the scope.

    This has a consequence:
    The allocated memory still exists, but you can't access it anymore (the socket variable).

    What you need to do:
    Manage all your pointers.
    If there isn't a parent/child relationship where the parent frees all the child allocations, or in the case the lifetime of the parent is too long (as in the parent exists for the duration the program is being run), then you need to explicitly free the resources yourself.

    Thus:
    In your case, just before the scope of the function ends, you should delete the memory allocated. This, of course, will make your program not work anymore like you expect it.

    Thus:
    You should really define your pointers at class level so they are accessible everywhere in the class for the lifetime of an object based on that class.

  5. The following user says thank you to tbscope for this useful post:

    dreac (31st July 2011)

  6. #5
    Join Date
    Jul 2011
    Posts
    3
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    1

    Default Re: QTcpSocket - memory allocation problem

    Thank you again for your quick reply.

    Well, I see your point in this. I agree that this isn't clean and it should be solved in a smarter way.

    If you replace the TcpServer class with the following code then you don't lose access to 'socket' as it is a private member now, yet the problem remains. Also, in this case you can be sure that no more than 1 connection is open. Of course, this doesn't make much sense but serves as demonstration purpose only.

    Qt Code:
    1. class TcpServer : public QTcpServer
    2. {
    3. Q_OBJECT
    4. public:
    5. TcpServer ( QObject * parent = 0 ) : QTcpServer(parent)
    6. {
    7. this->socket = NULL;
    8.  
    9. if (!this->listen( QHostAddress::LocalHost, 2688))
    10. {
    11. exit(-1);
    12. }
    13. };
    14.  
    15. protected:
    16. virtual void incomingConnection ( int socketDescriptor )
    17. {
    18. if (this->socket == NULL)
    19. {
    20. this->socket = new ServerSocket(this);
    21. socket->setSocketDescriptor(socketDescriptor);
    22. connect(socket, SIGNAL(readyRead()), socket, SLOT(readBlockData()));
    23. }
    24. };
    25.  
    26. private:
    27. ServerSocket *socket;
    28.  
    29. };
    To copy to clipboard, switch view to plain text mode 



    Edit:
    I found the solution to my problem. Here it is. It was in the method readBlockData(). I commented out the line that caused problems and added the new lines. It was something with the QDataStream. My guess ... maybe something about null terminated data.

    Qt Code:
    1. void readBlockData()
    2. {
    3. QDataStream in(this);
    4. in.setVersion(QDataStream::Qt_4_7);
    5.  
    6. if (this->blockSize == 0)
    7. {
    8. if (this->bytesAvailable() < (int)sizeof(quint32))
    9. return;
    10.  
    11. in >> this->blockSize;
    12. }
    13.  
    14. if (this->bytesAvailable() < this->blockSize)
    15. return;
    16.  
    17. char* blockData = new char[this->blockSize];
    18.  
    19. // these lines caused the memory leak for whatever reason
    20. // in >> blockData;
    21. // QByteArray byteArray(blockData);
    22.  
    23. // new lines
    24. int bytesRead = in.readRawData(blockData, this->blockSize);
    25.  
    26. if (bytesRead != this->blockSize)
    27. {
    28. // do something here ...
    29. }
    30.  
    31. QByteArray byteArray(blockData, bytesRead);
    32. // end new lines
    33.  
    34. std::cout << (int)byteArray.size() << " - " << this->bytesAvailable() << "\n";
    35.  
    36. this->blockSize = 0;
    37.  
    38. delete[] blockData;
    39. };
    To copy to clipboard, switch view to plain text mode 

    Thanks tbscope for your input
    Last edited by dreac; 31st July 2011 at 11:55.

Similar Threads

  1. memory allocation problem
    By marc2050 in forum Newbie
    Replies: 7
    Last Post: 23rd May 2011, 09:05
  2. Widget Memory Allocation
    By ArlexBee-871RBO in forum Qt Programming
    Replies: 5
    Last Post: 9th May 2010, 19:51
  3. Virtual memory allocation problem
    By morfei in forum Qt Programming
    Replies: 1
    Last Post: 27th August 2009, 11:30
  4. limit memory allocation
    By magland in forum General Programming
    Replies: 10
    Last Post: 23rd March 2007, 09:21
  5. vector memory allocation
    By TheKedge in forum General Programming
    Replies: 1
    Last Post: 23rd March 2006, 17:27

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.