2

私は現在、I / Oデバイスと対話するプログラムを作成しており、イン/アウト接続をチェックするためにx秒ごとにデバイスをポーリングする方法が必要でした。これを行うために、タイマーとタイマーイベントハンドルを使用して、ポーリングを実行するスレッドを作成するボタンを使用しました。ただし、タスクマネージャーでは、時間が経つにつれて徐々にメモリを消費していることに気付きました。以下は、私の問題に関連する(私が思う)コードのスニペットです。

スレッドを作成するためのボタン:

private void btnConnect_Click(object sender, EventArgs e)
    {
        new Thread(start).Start();
    }

タイマーを含むスレッド:

        public void start()
    {
        timer = new System.Timers.Timer(1000);
        timer.Elapsed += new ElapsedEventHandler(timerElapsed);
        timer.Enabled = true;
    }

ElapsedEventHandler:

public void timerElapsed(object sender, ElapsedEventArgs e)
    {
        connect();
    }

そして最後にメソッドconnect();:

public void connect()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append(txtIPseg1.Text + "." + txtIPseg2.Text + "." + txtIPseg3.Text + "." + txtIPseg4.Text);
        int Port = int.Parse(txtPort.Text);
        string address = sb.ToString();

        //send data
        byte[] bData = new byte[71];
        bData[0] = 240;
        bData[1] = 240;
        bData[2] = 0;
        bData[3] = 1;
        bData[68] = 240;
        bData[69] = 240;
        bData[70] = this.CalculateCheckSum(bData);

        try
        {
            byte[] result = this.SendCommandResult(address, Port, bData, 72);
            if (result != null)
            {
                this.Invoke((MethodInvoker)delegate
                {
                    txtOutput1.Text = (result[4] == 0x00 ? "HIGH" : "LOW"); // runs on UI thread
                });
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }

    }

リークはタイマー、またはconnect();メソッドで使用されるanonデリゲートのいずれかから発生していると確信しています。誰かアイデアはありますか?

4

1 に答える 1

2

ボタンがクリックされるたびに新しいタイマーを作成しています。また、参照を保持していないため、ガベージコレクターによって破棄されます。タイマーは新しいスレッドでElapsedイベントを発生させるため、新しいスレッドでタイマーを開始する必要はありません。

class Form1 ...
{
    private System.Timers.Timer timer = null;

    public void start()
    {
    if (timer == null)
        {
        timer = new System.Timers.Timer(1000);
        timer.Elapsed += new ElapsedEventHandler(timerElapsed);
        }
    timer.Enabled = true;
    }

    ...
}

メモリリークに関しては、アプリケーションの実行中にメモリ使用量がランダムに変動しているように見えるからといって、メモリリークが発生しているとは思いません。これは、.NETなどの複雑なフレームワーク内で実行している場合の通常の動作です。タイマーが起動するたびに、接続メソッドが呼び出され、新しいオブジェクトが作成されます。これらのオブジェクトは、ガベージコレクターがそれらをクリーンアップするまでメモリに残ります。そのため、メモリが急上昇し、数分後に突然再びドロップダウンするのを見るのはまったく驚くべきことではありません。それがずっと長い期間にわたって制御不能になり続けない限り、私は問題を疑うことはありません。

StringBuilderクラスの使い方もおかしいです。何をしているの:

StringBuilder sb = new StringBuilder();
sb.Append(txtIPseg1.Text + "." + txtIPseg2.Text + "." + txtIPseg3.Text + "." + txtIPseg4.Text);
string address = sb.ToString();

これを行うよりも良いことはありません(実際には少し悪いです):

string address = txtIPseg1.Text + "." + txtIPseg2.Text + "." + txtIPseg3.Text + "." + txtIPseg4.Text;

より効率的で、おそらく読みやすい方法を探している場合は、次のような方法を試してください

string address = string.Format("{0}.{1}.{2}.{3}", txtIPseg1.Text, txtIPseg2.Text, txtIPseg3.Text, txtIPseg4.Text);

しかし、メモリリークを引き起こすものとして私に飛び出すものは何もないので、あなたがそう考える正当な理由がない限り、私はそれについて心配しません。

于 2012-05-18T14:40:51.200 に答える