分配带数组的Range时出现VBA内存问题

时间:2012-04-30 10:06:34

标签: excel vba memory range memory-leaks

我的目的是为Excel范围的单元格指定二维变量数组的值。

该分配工作正常,但我遇到了内存问题(泄漏):当我启动Excel时,该过程需要或多或少22 Mo的Ram。运行以下代码(创建新工作簿,分配范围,关闭工作簿而不保存)后,该过程需要33 Mo的RAM。

有没有人知道我做错了什么?

此致 亚历山大

这里是代码

Option Explicit

Sub test()
   Dim nLines As Long
   Dim xSize As Long
   Dim j As Long
   Dim i As Long

   'Creating New Empty Workbook
   Application.Workbooks.Add
   Range("A1").Select

   Application.ScreenUpdating = False

   nLines = 10000
   xSize = 200

   Dim myRange As Range
   Dim myArray() As Variant

   ReDim myArray(1 To nLines, 1 To xSize)

   'Assigning some values
   For j = 1 To nLines:
       For i = 1 To xSize:
        myArray(j, i) = i * 4 / 3#
       Next i
   Next j

   Set myRange = Range(ActiveCell, ActiveCell.Offset(nLines - 1, xSize - 1))
   myRange .Value = myArray

   'Cleaning up
    Erase myArray
    Set myRange = Nothing

    'Closing workbook without saving
    Application.ActiveWorkbook.Close (False)

    Application.ScreenUpdating = True

End Sub

1 个答案:

答案 0 :(得分:8)

VBA不是C,不依赖于能够以任何方式控制Excel的内存占用。 Excel在内存管理方面本身并不擅长,而且往往是你运行宏或你在这些宏中做的事情几乎无法控制Excel决定分配多少内存,或者它是否曾经决定再次释放它。

话虽如此,您可以在代码中执行一些操作来尝试减少其混乱。

  1. Range("A1").Select

      

    在Excel中对单元格进行操作之前选择单元格通常是不好的做法。您需要选择单元格的唯一时间是您向宏的查看器说明内容。此外,这个代码实际上可能会导致excel的某些版本出现问题,因为你刚刚添加了一个工作簿,而且没有什么可以告诉excel什么工作簿,以及它应该选择的工作表中的工作表。您应该完全删除此代码(无论如何它都不会影响您的逻辑)。

  2. Set myRange = Range( ...

      

    此代码不是必需的,因为您只对范围执行一个操作。您根本不需要创建myRange变量,因此您也不必担心将其设置为空,或者更重要的是 - 将其设置为空的这一事实实际上并没有实现任何内存方式。< / p>

  3. ActiveCellApplication.ActiveWorkbook

      

    同样,基于对“选择”和“ActiveWorkbook”的调用的这些不合格的引用并不明确,并且可能导致不可靠的行为,尤其是当用户在同一个excel实例中打开其他电子表格时。您最好存储对您在开始时添加的工作簿的引用。

  4. 总而言之,我会将您的代码更改为:

    Sub test()
        Const nLines As Long = 10000, xSize As Long = 200
        Dim i As Long, j As Long
        Dim newWorkbook As Workbook
    
        Application.ScreenUpdating = False
    
        'Creating New Empty Workbook
        Set newWorkbook = Application.Workbooks.Add
    
        'Assigning some values
        Dim myArray(1 To nLines, 1 To xSize) As Double
        For j = 1 To nLines:
           For i = 1 To xSize:
            myArray(j, i) = i * 4 / 3#
           Next i
        Next j
    
        With newWorkbook.Sheets(1)
            .Range(.Cells(1, 1), .Cells(nLines - 1, xSize - 1)).Value = myArray
        End With
    
        'Closing workbook without saving
        newWorkbook.Close (False)
    
        'Cleaning up
        Erase myArray
        Set newWorkbook = Nothing
    
        Application.ScreenUpdating = True
    End Sub
    

    结束语:

    除了VBA编码课程 - 请注意,打开新工作簿的行为将要求Excel分配大量新内存 - 而不是创建临时数组。即使在关闭新工作簿之后,这也是可以自由或保持存在的内存。这些增加将无法解决。请注意,Excel的内存占用量与您当前的工作簿无关,它是实例的整个生命周期(支持多个工作簿),以及它们的备份,优化的计算树,撤消历史记录等。它真的没有意义将新推出的excel实例的足迹与刚刚完成的“一堆东西”的实施例进行比较。

    另请注意,仅仅因为Excel不决定释放该内存,它不会使其成为泄漏。 Excel可能已在可循环/可重用对象中分配内存,这些对象将使用您决定打开的下一个工作簿重新填充。反复重新运行代码可能会导致每次内存略有增加,但Excel也可以跟踪一定量的实例操作历史记录。

    To(传闻)说明了我的观点,这是Excel(2007)在打开一个新实例,运行代码一次,再运行9次,然后再运行40次之后的内存占用情况。

    enter image description here

    这不是您的代码的错,您不担心责任,如果您的业务用户担心,他们不应该选择旧版本的Excel作为他们的目标开发平台。