2016-12-16 5 views
-2

私はVisual Studio Community 2015でC++でQt 5.7を使用しています。Qtのリソースコントロールについて知っているのは、親を殺すと、その親オブジェクトへのポインタの子。しかし、私が試したとき、私はその方向を指し示す結果を得ていなかったので、なぜそれが見えないのですか。親ウィジェットを破棄するとQt 5.7がリソースを返さない

以下のコードを実行して参照ポイントを取得します。コードブロックがコメントアウトされていますのでご注意ください:

#include <QtWidgets/QApplication> 
#include <QWidget> 
#include <QPushButton> 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    QWidget* w0 = new QWidget; 
    /* 
    QWidget* w1 = new QWidget; 
    w1->setWindowTitle("Window 1"); 
    for(size_t i = 0; i < 1000; i++) { 
     QPushButton* pb = new QPushButton(w1); 
    } 
    w1->show(); 
    */ 
    w0->show(); 
    return a.exec(); 
} 

このコードを実行すると、VSはプロセスメモリが4 MBであることを示します。

enter image description here

そして私はより多くのメモリを使用するために、コードの下に実行されます。コメントブロックのない同じコード:

#include <QtWidgets/QApplication> 
#include <QWidget> 
#include <QPushButton> 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    QWidget* w0 = new QWidget; 

    QWidget* w1 = new QWidget; 
    w1->setWindowTitle("Window 1"); 
    for(size_t i = 0; i < 1000; i++) { 
     QPushButton* pb = new QPushButton(w1); 
    } 
    w1->show(); 

    w0->show(); 
    return a.exec(); 
} 

今回は、9 MBのメモリを使用しました。

enter image description here

これまでのところは良いです。ここで私が期待しているのは、w1を破棄すると、その子オブジェクト(プッシュボタン)で使用されているリソースが返され、使用されるメモリが少なくなるはずです。しかし、それは起こりません。私はw1を殺すとw0はまだ実行されているので、メモリ使用量を観察することができます.w0はw1の親ではなく、すべてのプッシュボタンはw1の子ですが、メモリは返されません。私は何をしているのか、間違って理解しています

更新:上記の例では、w1が指すウィンドウを閉じて(Xをクリックするだけで)、ポインタw1も削除すると思いますが、テストするために、以下のコードとそのコードを実行しました6 MBのメモリを使用します。だから、明らかに3メガバイト以下に

delete w1; 

新しいコードの追加後に返されます。

#include <QtWidgets/QApplication> 
#include <QWidget> 
#include <QPushButton> 

int main(int argc, char *argv[]) { 
    QApplication a(argc, argv); 
    QWidget* w0 = new QWidget; 

    QWidget* w1 = new QWidget; 
    w1->setWindowTitle("Window 1"); 
    for(size_t i = 0; i < 1000; i++) { 
     QPushButton* pb = new QPushButton(w1); 
    } 
    w1->show(); 

    w0->show(); 
    delete w1; 

    return a.exec(); 
} 

をが、2メガバイトリークが依然として存在しています。この時点で2つの質問:

1.なぜ私は明示的にw1を削除する必要がありますか?なぜウィンドウを閉じるだけで十分ではないのですか? 2.明示的にw1を削除してもまだリークはありますか?

+0

あなたは* 'w0'と' w1'をいかに正確に殺していますか?あなたはあなたのコードにそれを示していません。 – Mike

+0

上記の例では、w1が指し示しているウィンドウを閉じるだけで、ポインタも破棄されると考えていました(そうですか?)。今私はテストを実行し、 'w0-> show();'の下に 'delete w1;'を追加しました。そして、今使っているメモリは6 MBです。まだ4 MBではありません。だから明らかにはい私は自分自身をポインタを削除するときに違いがありますが、それはまだ漏れているようだ、と私は、ウィンドウを閉じるには、使用されるメモリを返すために十分でなければならないと思う。 – Deniz

+1

いいえ、[WA_DeleteOnClose'属性を設定する](https://doc.qt.io/qt-5/qwidget.html#close)を設定しない限り、ウィンドウを閉じることで削除されません。それを設定しましたか? – Mike

答えて

4

オペレーティングシステムのメモリマネージャが、割り当てられていない各ヒープメモリバイトを解放する必要はありません。通常それはしません。しかし、それはメモリが漏れたことを意味しません。

たとえば、5 MBのメモリ使用量から始めて5 MBのオブジェクトを割り当て、割り当てを解除すると3 MBしか解放されずに7 MBの使用量が残されます。しかし、5メガバイト分のオブジェクトを再度割り当てると、メモリ使用量は12メガバイトにジャンプせず、まだ解放されていない2メガバイトが再利用されるため、10にジャンプします。

見てくださいhere、私はそのような問題を調査しました。ご覧のように、しばらくの間、メモリの使用量は41から53MBに増え続けますが、安定し、数百回の割り当て/割り当て解除の後でさえもそれ以上には増加しません。異なるOSメモリマネージャは異なる方法で動作します。総メモリ量と空きメモリ量も要因になります。おそらくアプリケーション自体の使用パターンでもあります。

メモリ使用量が2 MB増加し、安定したレベルに達することがないたびにリークと見なすことができます。デストラクタでデバッグメッセージを使用してカスタムウィジェットを作成すると、そのウィジェットとその子が破棄されているかどうか、またその子が破棄されているかどうかを確認できます。しかし、ここでも、使用済みメモリーの100%を回収するという保証はありません。

+0

それは非常に良い点です、私は私の答えで言及するつもりでしたが、VS2015がメモリモニタで表示されているそれは、OSの観点からメモリ使用量を表示することができますし、完全に正しいか理論的には、C++ランタイムを介して適切な割り当てを示すことができます。その後、理論上、OSからのメモリ割り当ての影響を受けてはなりません。それでも私はそれをテストすることはできません..しかし、私はあなたの答えに投票するだろう=) – evilruff

+0

@ evilruffさんとマイクのコメントは、私がクローズ時にオブジェクトを破壊するフラグについて知らせてくれました。しかし、本当に私のことを明らかにしたのはあなたの答えだったので、私は受け入れられた答えとしてそれを設定しています。私はMikeとevilruffの回答をアップvしてくれたので、彼らも私を助けました。 3つすべてありがとうございます。 – Deniz

1

あなたが仮定したことは間違っています。その後、ウィンドウを閉じると、それはただの信号で隠れてしまいます。フラグQt::WA_DeleteOnCloseを設定していない限り、デストラクタ呼び出しはありません。その後、ウィジェットは終了時に削除されます。

+0

ありがとうございます。しかし、明示的な 'delete w1; 'を含む新しいテストで私の質問を更新しました.3 MBを返しますが、まだ2 MBのリークがあります。この状況をどのように解釈すべきですか? – Deniz

+1

さて、Qt内部では多くの内部初期化が行われています。例えば、QPushButtonのような別のコンポーネントを使用しています。それは、キャッシュされた別の種類のものを作成します。例えば、それ以降にQPushButtonsをさらに作成する場合などです。正直言って私は気にしません。あなたのコードにループを置くと10000回繰り返すと何も間違いは見えません本当に起こる – evilruff

+0

また、多くのものはdeleteLater()を使用して削除されますので、イベントループの後にのみ発生します – evilruff

関連する問題