【问题标题】:Workaround for Memory Leak when using large string使用大字符串时内存泄漏的解决方法
【发布时间】:2018-09-19 17:19:26
【问题描述】:

以下简单代码将一些单元格复制到剪贴板并将其作为文本数据取回。稍后此数据将被发布到内部网络服务,但此时已将其注释掉。 每次我运行脚本时,Excel 的已用内存都会增加大约 80MB(字符串大小的两倍)。我不知道垃圾收集器在哪里/为什么失败以及我能做些什么。

Sub memory_leak()
    Dim DataObj As New MSForms.DataObject
    Dim data As String

    'Copy Data Range ~ the first 250.000 rows / 22 columns
    Range(Cells(9, 1), Cells(250000, 22)).Copy

    DataObj.GetFromClipboard
    data = DataObj.GetText

    ' Call postToURL("http://intranet/API.php?action=test", data)

    'Try to free memory...
    Application.CutCopyMode = False
    DataObj.Clear
    data = ""
End Sub

【问题讨论】:

  • 将它发送到剪贴板并执行.GetText 有什么意义?为什么不直接使用Range(...).Values
  • Dim .... As New 正在声明一个自动实例化的对象,这意味着DataObj 不能真正被销毁(尝试Set DataObj = Nothing 然后Debug.Print DataObj Is Nothing)。我会从Set在单独的指令中开始。
  • @BruceWayne:Range..Values 给出了一个 2D 数组,这几乎是不可能使用的,然后试图从中创建一个字符串。在循环结构时,我所有的尝试都会导致非常(非常)大的运行时间。而Join 仅适用于一维数组。
  • @MathieuGuindon:有趣的一点。 “将其设置在单独的指令上”到底是什么意思?我只是试图在全​​局范围内调暗 DataObj 以强制重用,但这会导致另一个错误(DataObject:GetText Data in clipboard is invalid)
  • VBA 不是垃圾收集的,它是引用计数的。请注意,Dim 语句是不可执行的(您不能在它们上放置断点),但 Set 语句是可执行的。所以Dim DataObj As MSForms.DataObject 和下一行Set DataObj = New MSForms.DataObject 就是我的意思。也就是说问题可能出在其他地方,但Dim ..As New 不可能有帮助。

标签: excel vba


【解决方案1】:

根本原因不是处理大字符串。问题是调用MSForms.DataObj.GetText 方法不能正确释放内存。 剪贴板访问也可以通过本机 Windows API 完成。这个站点http://access.mvps.org/access/api/api0049.htm 展示了一个示例实现,它在我的测试中运行良好,即使它比 MSForms 提供的方法慢约 30%。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    • 2013-04-01
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多