2

私の目的は、Excel のセル範囲にバリアントの 2 次元配列の値を割り当てることです。

割り当ては正常に機能しますが、メモリの問題 (リーク) に直面しています。Excel を起動すると、プロセスに RAM の 22 Mo が多かれ少なかれかかります。次のコード (新しいワークブックの作成、範囲の割り当て、保存せずにワークブックを閉じる) を実行した後、プロセスは 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 は C 言語ではありません。Excel のメモリ フットプリントを何らかの方法で制御できるとは考えないでください。Excel は、それ自体でメモリ管理を行うことは得意ではありません。多くの場合、マクロを実行しているという事実、またはそれらのマクロで行っていることは、Excel が割り当てを決定するメモリの量、または割り当てを行うかどうかをほとんど、またはまったく制御できません。再び解放することにしました。

そうは言っても、混乱を減らすためにコードでできることがいくつかあります。

  1. Range("A1").Select

    一般に、Excel で操作する前にセルを選択することはお勧めできません。セルを選択する必要があるのは、マクロのビューアに何かを説明する場合のみです。さらに、ワークブックを追加したばかりで、どのワークブックと、そのワークブックからどのワークシートを選択する必要があるかを Excel に伝えるものがないため、このコードは実際に特定のバージョンの Excel で問題を引き起こす可能性があります。このコードを完全に削除する必要があります (ロジックには影響しません)。

  2. Set myRange = Range( ...

    範囲で 1 つのアクションしか実行していないため、このコードは必要ありません。myRange 変数をまったく作成する必要がないため、変数を何も設定しないことを心配する必要もありません。さらに重要なことに、変数を何も設定しても実際にはメモリに関して何も達成されないという事実です。

  3. ActiveCellApplication.ActiveWorkbook

    繰り返しになりますが、'Select' と 'ActiveWorkbook' の呼び出しに基づくこれらの非修飾参照は明示的ではなく、特にユーザーが Excel の同じインスタンスで他のスプレッドシートを開いている場合、信頼できない動作を引き起こす可能性があります。最初に追加したワークブックへの参照を保存することをお勧めします。

全体として、コードを次のように変更します。

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 は一定量のインスタンス アクション履歴を追跡することもできます。

(逸話的に) 私の要点を説明するために、新しいインスタンスを開いてコードを 1 回、さらに 9 回、その後さらに 40 回実行したときの Excel (2007) のメモリ フットプリントを次に示します。

ここに画像の説明を入力

それはあなたのコードのせいではありません。それについて心配する責任はあなたにありません。ビジネス ユーザーが心配している場合は、対象の開発プラットフォームとして古いバージョンの Excel を選択するべきではありません。

于 2012-04-30T20:06:25.893 に答える