我正在用C++/Qt開發下載服務器。我正面臨記憶日益增長的問題。在這裏,我分享示例服務器應用程序來演示該問題。服務器內存增長
當客戶端連接時,它開始每秒發送10Kb數據塊。當客戶端斷開時,套接字被刪除。
#include <QCoreApplication>
#include <QtNetwork>
class Client: public QObject
{
Q_OBJECT
public:
Client(QSslSocket *sock)
{
this->timer = new QTimer(this);
this->timer->setInterval(1000);
connect(this->timer, SIGNAL(timeout()), this, SLOT(sendData()));
this->sock = sock;
connect(sock, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
connect(sock, SIGNAL(encrypted()), this->timer, SLOT(start()));
connect(sock, SIGNAL(readyRead()), this, SLOT(readData()));
}
~Client()
{
delete this->sock;
}
void start()
{
this->sock->startServerEncryption();
}
signals:
void disconnected();
private slots:
void sendData()
{
qDebug() << "sending data via socket: " << sock->socketDescriptor();
if (this->sock->bytesToWrite())
return;
QByteArray ba(10*1024, '1');
this->sock->write(ba);
}
void readData()
{
this->sock->readAll();
}
private:
QSslSocket *sock;
QTimer *timer;
}; // Client
class Server: public QTcpServer
{
Q_OBJECT
public:
Server()
{
this->totalConnected = 0;
this->instanceCounter = 0;
}
protected:
virtual void incomingConnection(int d);
private:
int totalConnected;
int instanceCounter;
private slots:
void handleClientDisconnected();
void handleDestroyed();
}; // Server
void Server::incomingConnection(int d)
{
QSslSocket *sock = new QSslSocket(this);
if (!sock->setSocketDescriptor(d))
{
delete sock;
return;
}
++this->instanceCounter;
qDebug() << "socket " << d << "connected, total: " << ++this->totalConnected;
sock->setLocalCertificate(":/ssl/resources/my.crt");
sock->setPrivateKey(":/ssl/resources/my.key", QSsl::Rsa, QSsl::Pem, "my.pass");
Client *client = new Client(sock);
connect(client, SIGNAL(disconnected()), this, SLOT(handleClientDisconnected()));
connect(client, SIGNAL(destroyed()), this, SLOT(handleDestroyed()));
client->start();
}
void Server::handleClientDisconnected()
{
qDebug() << "client disconnected, total: " << --this->totalConnected;
sender()->deleteLater();
}
void Server::handleDestroyed()
{
qDebug() << "destroyed: " << --this->instanceCounter;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Server server;
if (server.listen(QHostAddress::Any, 563))
qDebug() << "listen started";
else qDebug() << "listen failed";
return a.exec();
}
#include "main.moc"
有關於它的兩個問題:
1)爲什麼記憶不斷在下載成長?
我正在測試200-300連接。它在幾分鐘內達到了400 Mb並且不會停止。
在客戶端:: sendData我檢查this-> sock-> bytesToWrite()知道是否有什麼等待寫入。因此,在寫入所有內容之前,不會添加新數據。所有的數據塊都具有相同的大小,所以它不能爲新的數據分配更多的內存。
2)爲什麼不關閉所有連接都返回的內存?
雖然下載時使用的內存在客戶端斷開連接時斷開,但看起來並不是全部都返回。經過幾次建立200-700個連接的測試後,達到80 Mb,並且在根本沒有客戶端(客戶端對象全部被報告銷燬,實例計數器變爲零)時始終保持在該水平。
我在讀關於對象刪除和內存釋放的區別。據我瞭解,系統可能會爲未來的需求(某種優化)預留它。但是當別的東西需要時,它肯定必須返回這個記憶。我決定編寫一個分配大量內存(即數組)的小程序,以查看它是否會使系統兌換服務器使用的內存。它沒有。該程序崩潰,因爲沒有足夠的內存(它在服務器剛啓動時工作正常)。
所以看起來有什麼問題。我懷疑泄漏,但內存泄漏檢測器似乎沒有注意到任何嚴重問題。 Visual Leak Detector報告說沒有內存泄漏。 Valgrind報告了一些問題,但他們指的是Qt庫,我在讀它們只是虛驚一場,通常只是valgrind之後釋放內存的低級庫的副作用。無論如何,據報道丟失數據的總量與80 Mb相比非常小。