none
VB2005 程式的記憶體使用量. 會一直增加?? RRS feed

  • 問題

  • 我的程式有一個無限迴圈, 會經由 RS232 讀取主機狀態, 並解析狀態, 但是我用 windows 工作管理員查看我的程式, 為什麼我的程式記憶體使用量, 會緩慢的增加, 每次都增加4k, 請問要怎麼解決呢??

     

    還有, 程式的記憶體使用量, 增加了以後, 好像都不會減少..??

     

    以下是我程式的片段, 部份副程式用 xxx 取代..

    Code Snippet

     

            Do While _ExitLoop = False

                My.Application.DoEvents()
                System.Threading.Thread.Sleep(1)

                '判斷是否要暫停輪詢
                If _Pause = True Then
                    _PauseOK = True
                    Continue Do
                Else
                    _PauseOK = False
                End If

     

                '---------------------------------------------------
                If _xxx1 = True Then
                    If _xxx2(0, strCode) = True Then
                        If strCode <> "" Then
                            If strCode <> "000000000000" Then
                                RaiseEvent _xxx3(strCode)
                            End If
                        End If
                    End If

                End If

     


                '---------------------------------------------------
                If _xxx4(0).strIndex = "" Then Continue Do


                intID = _xxx4(AskIndex).ID
                intID_2 = intID Or (2 ^ 6)


                '---------------------------------------------------
                If _Pause = True Then Continue Do
                If _ExitLoop = True Then Exit Do


                '主要機器
                If _xxx5(intID, IIf(_xxx4(AskIndex).bteState = 0, False, True), lngSerial) = True Then

                    With _xxx4(AskIndex)
                        If .bteState = 0 Then   '恢復連線
                            .bteState = 1
                            RaiseEvent Connect(.ID)
                        End If
                    End With

                    '主機正常
                    If _isFirst = False AndAlso lngSerial > 0 Then
                        '有按下遙控器
                        RaiseEvent _xxx6(intID)
                    End If
                Else
                    '主機失去連線
                    With _xxx4(AskIndex)
                        If .bteState = 1 Then   '主機斷線
                            .bteState = 0
                            RaiseEvent Lose(.ID)
                        End If
                    End With
                End If
                'System.Threading.Thread.Sleep(_SleepTime)


                '次要機器
                If _xxx4(AskIndex).MinorEngine = True Then
                    If _xxx5(intID, _isFirst, lngSerial) = True Then

                        'With _xxx4(AskIndex)
                        '    If .bteState = 0 Then   '恢復連線
                        '        .bteState = 1
                        '        RaiseEvent Connect(.ID)
                        '    End If
                        'End With

                        '主機正常
                        If _isFirst = False AndAlso lngSerial > 0 Then
                            '有按下遙控器
                            RaiseEvent _xxx6(intID)
                        End If
                    Else
                        '主機失去連線
                        If _isFirst = True Then
                            _xxx4(AskIndex).MinorEngine = False
                        Else
                            'With _xxx4(AskIndex)
                            '    If .bteState = 1 Then   '主機斷線
                            '        .bteState = 0
                            '        RaiseEvent Lose(.ID)
                            '    End If
                            'End With
                        End If
                    End If

                    'System.Threading.Thread.Sleep(_SleepTime)
                End If

     

     

                '---------------------------------------------------
                '詢問有無按下Key
                If _Pause = True Then Continue Do
                If _ExitLoop = True Then Exit Do


                '主要機器
                If _xxx4(AskIndex).bteState = 1 Then
                    If _xxx7(intID, True, bteState) Then
                        '正常
                        If _isFirst = False AndAlso bteState > 0 Then
                            '有按下Key
                            RaiseEvent _xxx8(intID, bteState)
                        End If
                    Else
                        '主機失去連線
                        With _xxx4(AskIndex)
                            If .bteState = 1 Then   '主機斷線
                                .bteState = 0
                                RaiseEvent Lose(.ID)
                            End If
                        End With
                    End If
                End If
                'System.Threading.Thread.Sleep(_SleepTime)


                '次要機器
                If _xxx4(AskIndex).MinorEngine = True Then
                    If _xxx7(intID_2, _isFirst, bteState) Then
                        '正常
                        If _isFirst = False AndAlso bteState > 0 Then
                            '有按下Key
                            RaiseEvent _xxx8(intID, bteState)
                        End If
                    Else
                        '主機失去連線
                        'With _xxx4(AskIndex)
                        '    If .bteState = 1 Then   '主機斷線
                        '        .bteState = 0
                        '        RaiseEvent Lose(.ID)
                        '    End If
                        'End With
                    End If
                End If

     

                ''---------------------------------------------------
                If _Pause = True Then Continue Do
                AskIndex = AskIndex + 1
                If AskIndex > _xxx4.Length - 1 Then
                    AskIndex = 0
                    _isFirst = False
                    System.GC.Collect()
                End If
            Loop


     

     

    2008年10月1日 上午 09:02

解答

  • 用下面程式碼測試:

    Code Snippet

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

         For i As Integer = 1 To 50

              Dim fOpen As New testImage

              fOpen.Show()

              System.Threading.Thread.Sleep(500)

              fOpen.Close()

              System.Threading.Thread.Sleep(500)

              GC.Collect()

         Next

    End Sub 

     

     

    用工作管理員觀察:

    1. 若將 GC.Collect() 註解掉,程式碼記憶體使用量會數次快速增加 5 MB 後,自動清除,如此循環。

    2. 在使用 GC.Collect() 下,程式碼記憶體使用量約在 100 kb 誤差下跳動。

     

    推測:

    可能是與回收記憶體的單位有關,比如說以節區為單位 (1 節區為 64 kb) ,所以小量的記憶體損耗沒有立即回收。

    2008年10月1日 下午 02:03

所有回覆

  • 定時呼叫 GC.Collect()

     

    VBNET 雖然會自動釋放記憶體,但多數的記憶體通常在程式結束才釋放。

    2008年10月1日 上午 09:28
  • 我己有定時呼叫  GC.Collect() 了, 但是我的程式一直肥大, 有無辨法解決嗎???

    2008年10月1日 上午 09:31
  • 那就表示你還有其它記憶體沒有正確釋放。

    2008年10月1日 上午 09:43
  • 補充:

    GC.Collect 只會回收參照數歸 0 的記憶體,只有參考變數才會有參照數。

     

    靜態記憶體整個程式執行期間都不會增減,例如一般實值變數。

     

    動態記憶體才會在程式執行期間增減,所有的參考變數都是。例如:物件、陣列。

     

    字串實際上是參考變數,但在操作時會當成實值變數。

     

    所以請檢查所有物件、陣列的使用狀態,是否都有釋放。
    2008年10月1日 上午 09:48
  • 那假設..

    dim aaa as new form

    然後按 aaa 視窗的右上角 "X" 來開閉視窗.. 再用 GC.Collect, 會回收記憶體嗎??

    因為我目前測試的結果是一直肥大....  = =|||

     

     

    2008年10月1日 下午 12:34
  • 用下面程式碼測試:

    Code Snippet

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

         For i As Integer = 1 To 50

              Dim fOpen As New testImage

              fOpen.Show()

              System.Threading.Thread.Sleep(500)

              fOpen.Close()

              System.Threading.Thread.Sleep(500)

              GC.Collect()

         Next

    End Sub 

     

     

    用工作管理員觀察:

    1. 若將 GC.Collect() 註解掉,程式碼記憶體使用量會數次快速增加 5 MB 後,自動清除,如此循環。

    2. 在使用 GC.Collect() 下,程式碼記憶體使用量約在 100 kb 誤差下跳動。

     

    推測:

    可能是與回收記憶體的單位有關,比如說以節區為單位 (1 節區為 64 kb) ,所以小量的記憶體損耗沒有立即回收。

    2008年10月1日 下午 02:03
  • 那自己在副程式宣告的變數要自己把它設定為 nothing 嗎?? 上網找一些文章都沒有找到.

    Code Snippet

    private sub QQQ()

       dim aaa as string

       aaa = "1234567890"

       aaa = nothing

    end sub

     

     

     

    2008年10月1日 下午 03:07
  • 物件變數才需要設為 Nothing 來減少參照數。

     

    字串前面特別有提:

     

    Code Snippet
    字串實際上是參考變數,但在操作時會當成實值變數。

     

     

    所以不用特別處理字串。

    2008年10月1日 下午 04:11
  • 那字串陣列, 數值變數, 數值陣列呢?? 也是一樣的嗎? 不用特別處理??

     

    視窗內一些副程式, 有用到一些物件, 如

    Code Snippet
    Dim sqlCMD As System.Data.OleDb.OleDbCommand
    Dim da As System.Data.OleDb.OleDbDataAdapter
    Dim tab As New System.Data.DataTable

     

     

    是否要將這些物件 Dispose, 再關閉視窗, 還是直接關閉視窗就好了? 

    因為一些資料上講說, 存在副程式內的變數, 如果離關該副程式, 變數就會釋放記憶體...

     

    2008年10月1日 下午 04:30
  • 前面說過:

    Code Snippet

    動態記憶體才會在程式執行期間增減,所有的參考變數都是。例如:物件、陣列

     

     

    假設:

    Code Snippet

    Dim a(10) As Object

    Dim b As Object

    b = a

     

     

    b 用 Nothing 處理,因為 b 本身是參照。

    a 用 Erase 處理。

    2008年10月2日 上午 02:58