2

我的目的是用二维变量数组的值分配一个 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
4

1 回答 1

10

VBA isn't C, don't count on being able to control Excel's memory footprint in any way. Excel isn't great at memory management all on its own and often times the fact that you're running macros or what you're doing in those macros has little to no control on how much memory Excel decides to allocate, or whether it ever decides to free it up again.

That being said, there are a few things you can do in your code to try to reduce its mess.

  1. Range("A1").Select

    It's generally bad practice to select cells before operating on them in Excel. The only time you need to select a cell is if you are illustrating something to the viewer of the macro. Furthermore, this code can actually cause a problem in certain versions of excel since you just added a workbook and it there's nothing to tell excel what workbook, and what worksheet from that workbook it should be selecting. You should remove this code altogether (it doesn't impact your logic anyway).

  2. Set myRange = Range( ...

    This code isn't necessary since you're only performing one action with the range. You don't need to create the myRange variable at all, so you also don't have to worry about setting it to nothing, or more importantly - the fact that setting it to nothing doesn't actually accomplish anything memory-wise.

  3. ActiveCell and Application.ActiveWorkbook

    Again, these unqualified references based on calls to 'Select' and the 'ActiveWorkbook' aren't explicit, and can cause unreliable behavior, especially if the user has other spreadsheets open in the same instance of excel. You're better off storing a reference to the workbook you added in the beginning.

All in all, I would change your code to this:

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

Closing remarks:

VBA coding lessons aside - Note that the act of opening a new workbook will ask Excel to allocate a lot of new memory - way more than creating your temporary array. This is memory that is up to excel to free or keep around, even after you close the new workbook. There will be no getting around these kinds of increases. Note that the memory footprint of Excel isn't associated with just your current workbooks, it's the entire lifetime of the instance (which supports multiple workbooks), and their backups, optimized calculation trees, undo histories, etc. It really makes no sense to compare the footprint of a newly launched instance of excel to that of one that's just done 'a bunch of stuff'.

Also note that just because Excel doesn't decide to free that memory, it doesn't make it a leak. Excel might have allocated the memory in recyclable / reusable objects that will be repopulated with whatever next workbook you decide to open. Repeatedly rerunning the code may result in a small increase in memory each time, but Excel could just as well be tracking a certain amount of instance action history.

To (anecdotally) illustrate my point, here's the memory footprint of Excel (2007) upon opening a fresh instance, and running your code once, 9 more times, and then 40 more times after that.

enter image description here

It's not your code's fault, the onus is not on you to worry about it, and if your business users are worried about it, they shouldn't be choosing old versions of Excel as their target development platform.

于 2012-04-30T20:06:25.893 回答