none
[VB6]Array Virtual Bytes 使用超過 2GB RRS feed

  • 問題

  • 寫了一段處理報表的機制, 後來發現在資料量太大時會造成程式當機, 觀察後發現當機都是出現在當虛擬記憶體(Virtual Bytes)使用超過2GB當下
    觀察了程式的運行發現以下此段會造成問題, 請問有沒有辦法把以下這段的虛擬記憶體用量控制住在一定的範圍內呢?

    Option Explicit

    Private guSectionBuffer() As USR_SectionBuffer

    Private Type USR_CellBuffer
        Value As Variant
        LinkValue As String
        LinkFuncTag As String
        PriceFormatString As String
        MoneyFormatString As String
        ShipMarkBuffer    As Long
    End Type

    Private Type USR_RowBuffer
        Cells() As USR_CellBuffer
        IsHide As Boolean
        Height As Single
        ExtendRow As Boolean
        OrigRow As Long
        TestValue As String
    End Type

    Private Type USR_SectionBuffer
        Rows() As USR_RowBuffer
        IsHide As Boolean
        Height As Single
        RptSection As Long
        GroupFirst As Boolean
        GroupLast As Boolean
        ParentGroupIndex As Long
        GroupFootIndex  As Long
        IsAddRow As Boolean
        RecordPosition As Long
        OutermostGruopNo As Long
        BackColor As Long
    End Type

    Private Declare Function GetTickCount Lib "kernel32" () As Long

    Private Sub Command1_Click()
      Dim i As Long
      Dim j As Long
      Dim k As Long
      Dim iCount As Long
      Dim lngStart As Long
      Dim lngFinish As Long
      Dim iBound As Long
             
      ReDim guSectionBuffer(0)
      iCount = 60
     
      lngStart = GetTickCount()
     
      For i = 0 To iCount
        iBound = UBound(guSectionBuffer) + 1
        ReDim Preserve guSectionBuffer(iBound)
       
        'Initialize Rows
        ReDim Preserve guSectionBuffer(i).Rows(0)
        'Add Rows
        For j = 0 To 18000
          iBound = UBound(guSectionBuffer(i).Rows) + 1
          ReDim Preserve guSectionBuffer(i).Rows(iBound)
         
          guSectionBuffer(i).Rows(j).TestValue = "TEST VALUE"
         
          'Initialized Cells
          ReDim Preserve guSectionBuffer(i).Rows(j).Cells(0)
          'Add Cells
          For k = 0 To 36
            iBound = UBound(guSectionBuffer(i).Rows(j).Cells) + 1
            ReDim Preserve guSectionBuffer(i).Rows(j).Cells(iBound)
            guSectionBuffer(i).Rows(j).Cells(k).Value = "Test Cell"
          Next k
        Next j
      Next i
     
      lngFinish = GetTickCount()
     
      MsgBox CStr(lngFinish - lngStart)
     
      For i = 0 To iCount
        For j = 0 To 18000
          'free cell
          ReDim guSectionBuffer(i).Rows(j).Cells(0)
        Next j

        'free Row
        ReDim guSectionBuffer(i).Rows(0)
      Next i
     
      'Free Section
      ReDim guSectionBuffer(0)
    End Sub

    2009年6月2日 上午 04:35

解答

  • 記憶體 2 倍是瞬間大小,在工作管理員上看不出來。

    如果是計算,測試也請用實值變數,字串變數是由指標、字串結構、遠程字串內容組合而成,不但慢,記憶體使用量也比較多。

    既然是計算,必然有計算步驟,必然可將迴圈精簡記憶體使用量。

    例如超大矩陣做反矩陣,使用高斯消去法的話,也是以 Row 為單位,就可以先把 Row 存入磁碟或是只保留 1 Row, 1 Col 來計算,所以不會沒有不能精簡記憶體使用量的情形。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年6月2日 上午 06:43

所有回覆

  • 你這都是測試迴圈,看不出實際需求。

    重新檢討你的邏輯,把可以合併的功能寫在一起,累加的另外用變數記錄,降低陣列宣告大小。

    另外刪除陣列是用 Erase ,減少使用 ReDim Preserve ,不如一次開大點,成長一段時間再調整。

    ReDim Preserve 的過程:
    1. 在記憶體中找連續且足夠大的新空間。
    2. 鎖定該空間並將舊空間資料複製過來。
    3. 釋放舊空間。

    所以效能差,且要兩倍的空間。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年6月2日 上午 05:40
  • 實際需求大概是使用上面宣告的ARRAY去紀錄報表的計算與每個CELL的資料在跑另一個FUNCTION去把Array做輸出成HTML的動作
    由於程式太複雜我只把耗用虛擬記憶體的FUNCTION改為測試LOOP來做虛擬記憶體的測試

    測試先宣告Array大小在執行塞值對於記憶體的用量似乎差不多?不過速度是提升了大約一倍!
    修改後的Function如下: 

    'New Method
    Private Sub Command2_Click()
      Dim i As Long
      Dim j As Long
      Dim k As Long
      Dim iCount As Long
      Dim lngStart As Long
      Dim lngFinish As Long
      Dim iBound As Long
         
      ReDim guSectionBuffer(0)
      iCount = 60
      lngStart = GetTickCount()
     
      'Predefinde array size
      ReDim guSectionBuffer(iCount)
     
      For i = 0 To iCount
        'Set Row Count
        ReDim guSectionBuffer(i).Rows(18000)
       
        For j = 0 To 18000
          'Set Row Value
          guSectionBuffer(i).Rows(j).TestValue = "TEST VALUE"
         
          'Set Cell Count
          ReDim guSectionBuffer(i).Rows(j).Cells(36)
         
          For k = 0 To 36
            'Set Cell Value
            guSectionBuffer(i).Rows(j).Cells(k).Value = "TEST VALUE"
          Next k
        Next j
      Next i
     
      lngFinish = GetTickCount()
     
      MsgBox CStr(lngFinish - lngStart)
     
      For i = 0 To iCount
        For j = 0 To 18000
          'free cell
          Erase guSectionBuffer(i).Rows(j).Cells
        Next j
       
        'free Row
        Erase guSectionBuffer(i).Rows
      Next i
     
      'Free Section
      Erase guSectionBuffer
    End Sub

    2009年6月2日 上午 06:19
  • 記憶體 2 倍是瞬間大小,在工作管理員上看不出來。

    如果是計算,測試也請用實值變數,字串變數是由指標、字串結構、遠程字串內容組合而成,不但慢,記憶體使用量也比較多。

    既然是計算,必然有計算步驟,必然可將迴圈精簡記憶體使用量。

    例如超大矩陣做反矩陣,使用高斯消去法的話,也是以 Row 為單位,就可以先把 Row 存入磁碟或是只保留 1 Row, 1 Col 來計算,所以不會沒有不能精簡記憶體使用量的情形。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年6月2日 上午 06:43
  • 記憶體監控我是使用效能監視器去針對Process的Virtual Memory 和記憶體的Available MBytes做測試的
    記憶體用量用兩個Button分別去跑兩種做法比較圖形的差異感覺不是很大..

    由於光是跑Array的建立就耗完虛擬記憶體了所以我想針對此段先去做最佳化看看, 
    我在研究看看有沒有辦法精簡這個Array的資料量好了, 謝謝.

    2009年6月2日 上午 06:58