【问题标题】:Clear memory in vb6vb6清空内存
【发布时间】:2019-05-30 21:09:08
【问题描述】:
Option Explicit
Dim VBFlexGridCells() As String

Private Sub store_values()
On Error GoTo store_values_EH

Dim IndexLong As Long
Dim i As Integer
Dim entry As String
Dim rw As Integer

Dim aa As String
Dim bb As String
Dim cc As String
Dim dd As String
Dim ee As String
Dim jj As Integer
Dim ff As String
Dim ll As String
Dim mm As String
Dim nn As String
Dim kk As String

rw = 1
For rw = 0 To 15000
    aa = String(10000, "w")
    bb = String(125, "w")
    cc = String(125, "w")
    dd = String(125, "w")
    ee = String(125, "w")
    ff = String(125, "w")
    kk = String(125, "w")
    ll = String(125, "w")
    mm = String(125, "w")
    nn = String(125, "w")


    entry = aa & Chr(9) & bb & Chr(9) & cc & Chr(9) & dd & Chr(9) & ee & Chr(9) & ff & Chr(9) & kk & Chr(9) & ll & Chr(9) & mm & Chr(9) & nn

    IndexLong = IndexLong + 1
    ReDim Preserve VBFlexGridCells(10, IndexLong)

    Dim abc() As String
    abc = Split(entry, vbTab)
    For jj = LBound(abc) To UBound(abc)
        VBFlexGridCells(jj, IndexLong) = abc(jj)
    Next

Next

Exit Sub
store_values_EH:
MsgBox Err.Description & Space(10) & "store_values"
End Sub

在执行上述代码之前,我们的vb6程序使用的内存:17,720 KB

上面的代码执行后,我们的vb6程序使用的内存:386,836 KB

我们在代码执行后的内存使用近似值:320 MB 实际内存使用量和近似内存使用量在同一范围内 ~300MB

但是,当字符串 cc 增加到 126 个字符时,内存使用量会出现巨大的峰值。

cc = String(126, "w")

我们的vb6程序在代码执行后使用的内存:700.04 MB

我们在代码执行后的内存使用近似值:320 MB

内存使用量从 320 Mb 增加到 700 MB。类似地,当其他字符串增加到 126 chars 时,内存在 GB 范围内激增并导致“内存不足”错误。vb6 字符串附加似乎也存在一些问题(http://www.aivosto.com/articles/stringopt2.html“构建巨大的字符串”)

是否有任何选项可以检测和清除(取消分配)vb6 中未使用的内存?

【问题讨论】:

  • 当您删除redim preserve 并一次分配整个VBFlexGridCells(10, 15000) 时会发生什么?
  • @Gserg 没有变化,将达到 700 MB。
  • 如果整个字节长度 (4 + chars_count*2 + 2) 不大于 256,看起来 VB6 使用了一种优化的字符串处理方式,但这很奇怪,因为有问题的字符串不会改变并且不要直接存储,重要的是entry,但它的长度似乎无关紧要(例如,如果您将cc 增加到126 但将dd 减少到124,即使@ 987654334@ 长度保持不变)。似乎也没有内存泄漏,因为当你Erase VBFlexGridCells时,所有内存都回来了。
  • @GSerg for aa 到 16000 ,cc 到 125 ,内存使用量为 500 MB,然后将 cc 增加到 126 ,内存使用量为 1 GB。对于aa 到 16500,cc 到 125,内存使用量为 530 MB,但随后将cc 增加到 126,内存使用量仅为 530 MB。

标签: string memory-management vb6


【解决方案1】:

我真的不知道发生了什么,但它必须与 entry 最终包含的内部结构以及如何将其写入数组有关。如果在 entry 按原样生成时构造数组,则数组最终会消耗更多内存 - 数组是唯一可能分配内存的东西,没有任何“泄漏”。

为了更好地演示问题,让我们删除不需要的代码,简化数组边界声明并将除entry 赋值之外的所有内容移出循环:

Private Sub store_values()
  Dim entry As String
  Dim rw As Long

  Dim aa As String
  Dim bb As String
  Dim cc As String
  Dim dd As String
  Dim ee As String
  Dim jj As Long
  Dim ff As String
  Dim ll As String
  Dim mm As String
  Dim nn As String
  Dim kk As String

  aa = String(10000, "w")
  bb = String(125, "w")
  cc = String(126, "w") ' Increased from 125 to 126
  dd = String(125, "w")
  ee = String(125, "w")
  ff = String(125, "w")
  kk = String(125, "w")
  ll = String(125, "w")
  mm = String(125, "w")
  nn = String(125, "w")

  ReDim VBFlexGridCells(0 To 9, 1 To 15000)

  For rw = 1 To 15000
      entry = aa & Chr(9) & bb & Chr(9) & cc & Chr(9) & dd & Chr(9) & ee & Chr(9) & ff & Chr(9) & kk & Chr(9) & ll & Chr(9) & mm & Chr(9) & nn

      Dim abc() As String
      abc = Split(entry, vbTab)  ' Returns zero-based array
      For jj = LBound(abc) To UBound(abc)
          VBFlexGridCells(jj, rw) = abc(jj)
      Next
  Next
End Sub

运行此程序将消耗大约 700 Mb 的内存。

现在,如果我们将 entry 赋值移出循环:

ReDim VBFlexGridCells(0 To 9, 1 To 15000)

entry = aa & Chr(9) & bb & Chr(9) & cc & Chr(9) & dd & Chr(9) & ee & Chr(9) & ff & Chr(9) & kk & Chr(9) & ll & Chr(9) & mm & Chr(9) & nn

For rw = 1 To 15000
    Dim abc() As String
    abc = Split(entry, vbTab)  ' Returns zero-based array
    For jj = LBound(abc) To UBound(abc)
        VBFlexGridCells(jj, rw) = abc(jj)
    Next
Next

只会消耗大约 320 Mb,这真的很奇怪。

因此,获得正常内存消耗的一种选择是entry 分配移出循环

如果这不是一个选项(因为在生产代码中entry 在每次迭代中都不同),还有另一种方法:似乎复制数组也优化了它消耗的内存

    Dim temp_array(0 To 9, 1 To 15000) As String

    For rw = 1 To 15000
        entry = aa & vbTab & bb & vbTab & cc & vbTab & dd & vbTab & ee & vbTab & ff & vbTab & kk & vbTab & ll & vbTab & mm & vbTab & nn

        Dim abc() As String
        abc = Split(entry, vbTab)  ' Returns zero-based array
        For jj = LBound(abc) To UBound(abc)
            temp_array(jj, rw) = abc(jj)
        Next
    Next

    'Here we are consuming 700 Mb
    VBFlexGridCells = temp_array  ' Copying
    'Here we are consuming 1020 Mb
End Sub ' Here we are consuming 320 Mb

如果你有足够的内存在“正确”和“臃肿”数组同时存在的那一刻存活下来,那也可能是一个解决方案。

我真的很迷茫为什么会发生这种情况。

【讨论】:

    【解决方案2】:

    VB 中的每个字符串连接都会分配一个新的字符串,然后将数据复制过来,然后尽可能取消分配原始字符串。

    对于快速和内存优化的字符串连接,请使用 StringBuilder 类。如果您对字符串进行大量操作,例如连接、删除和替换,您的性能可能会受益于 System.Text 命名空间中的 StringBuilder 类。

    https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/operators-and-expressions/concatenation-operators

    【讨论】:

    • VB6中没有StringBuilder,与VB.NET不同的是,VB6中的字符串是可变的。
    • 我建议使用等效的字符串生成器,例如这里提到的 stackoverflow.com/questions/93932/… 或者只是在 google 中搜索 vb6 字符串生成器
    猜你喜欢
    • 2016-01-20
    • 2010-10-15
    • 2017-11-29
    • 2012-04-28
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    • 2017-10-20
    • 2015-04-14
    相关资源
    最近更新 更多