【入門編】VB.NETでの配列の初期化とReDim Preserveのパフォーマンス最適化:動的配列サイズ変更の罠とList(Of T)への移行 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

こんにちは!日々、コードと向き合ってお疲れ様です。
今日は、Visual Basic (VB.NET)でのデータ管理において、多くの開発者が知らず知らずのうちにハマってしまう「大きな罠」と、それを華麗に回避するための極意についてお話ししますね。

Excel VBAの「マクロの記録」から一歩踏み出し、本格的なVB.NETのアプリケーションを作り始めると、必ず直面するのが「要素数が事前に分からないデータの扱い」です。

ここをクリアすれば、あなたの書くコードは見違えるほど軽快になり、VB.NETの基本はもうバッチリと言えます。さあ、一緒に本質をマスターしていきましょう!

1. 悪魔の構文:`ReDim Preserve` の正体

データがいくつ来るか分からないとき、私たちはつい動的配列を使いたくなります。VB.NETには、配列のサイズを後から変更できる `ReDim` という便利なキーワードが用意されています。さらに、既存のデータを保持したままサイズを変える `ReDim Preserve` は、一見すると非常に強力です。

まずは、よくある「やってはいけない」コードを見てみましょう。

.net
‘ 【アンチパターン】ループの中で ReDim Preserve を使う例
Dim dataArray() As Integer = {} ‘ 空の配列
Dim recordCount As Integer = 0

For i As Integer = 1 To 10000
‘ データを追加するたびに配列を1つずつ広げる
recordCount += 1
ReDim Preserve dataArray(recordCount – 1)
dataArray(recordCount – 1) = i 10
Next

一見、何の問題もなさそうに見えますよね。「1から10万まで(ここでは1万ですが)データを綺麗に配列に格納できた!」と満足してしまいがちです。

しかし、バックステージ(メモリの世界)で何が起きているかを知ると、背筋が凍るはずです。

メモリの「引っ越し地獄」

コンピュータのメモリ上では、配列は「連続したひとまとまりの部屋」として確保されます。
`ReDim Preserve dataArray(recordCount – 1)` を実行した瞬間、VB.NET(正確にはCLR)は裏で以下のような重労働を強いられています。

1. 新しい広さの部屋を、メモリの別の場所に新しく確保する
2. 古い部屋にあるすべてのデータを、一言一句違わず新しい部屋にコピーする
3. 古い部屋を破棄する(ガベージコレクションの餌食にする)

これを要素が増えるたび(ループの回数分)に繰り返します。
つまり、1万回ループを回せば、メモリの確保とコピーが1万回行われるわけです。これは、荷物をダンボール1箱分詰めるたびに、家全体をより大きな家に引っ越し続けるようなもの。パフォーマンスがガタガタになるのは当然ですね。

2. 救世主:`List(Of T)`(ジェネリックリスト)への移行

「じゃあ、動的データを扱うときはどうすればいいの?」
安心してください。近代的な .NET の世界には、この引っ越し地獄をスマートに解決してくれる最高の相棒がいます。それが `List(Of T)`(ジェネリックリスト) です。

先ほどのコードを、`List(Of Integer)` を使って書き換えてみましょう。

.net
Imports System.Collections.Generic

Module Program
Sub Main()
‘ 【推奨アプローチ】List(Of T) を使用する例
Dim dataList As New List(Of Integer)()

For i As Integer = 1 To 10000
‘ Addメソッドで要素を追加するだけ!
dataList.Add(i 10)
Next

‘ 必要に応じて通常の配列に戻すことも可能
Dim finalArray() As Integer = dataList.ToArray()

Console.WriteLine(“データの数: ” & finalArray.Length)
End Sub
End Module

なぜ `List(Of T)` は速いのか?(裏側の仕組み)

`List(Of T)` は、内部で「あらかじめ少し大きめの配列」を確保しています。
要素を追加していき、その容量(キャパシティ)がいっぱいになると、「今あるサイズの倍の大きさの部屋」を一度だけ新しく確保し、データをコピーします。

つまり、1万回追加したとしても、メモリの再割り当てとコピーは数回しか発生しません。このアルゴリズム(償却 O(1) 時間計算量)により、`ReDim Preserve` とは比較にならないほどの圧倒的なパフォーマンスを発揮します。

3. 実務で役立つ!使い分けの判断基準

「じゃあ、これからは配列は一切使わずに、すべて `List(Of T)` にすべき?」という疑問が湧くかもしれません。
そこは百戦錬磨のエンジニアとして、適切な使い分けの基準をお伝えしておきましょう。

  • 配列 (`Array`) を使うべきケース
  • 要素数が絶対に変わらないことが最初から分かっている場合(例:曜日の数、固定のマスターデータなど)。
  • 最高のパフォーマンスと最小限のメモリ消費が求められる極限のチューニング時。
  • リスト (`List(Of T)`) を使うべきケース
  • ファイルから行数を読み込みながらデータを追加する場合。
  • ユーザーの操作によってデータが増減する場合。
  • 「要素数が事前に分からない」すべてのケース。(基本はこちらを選んでおけば間違いありません)

まとめ:ここをクリアすれば、VB.NETの基本はバッチリ!

今回は、VB.NETにおける動的配列の罠と、現代的なコレクションへの移行について解説しました。

1. `ReDim Preserve` の多用はメモリの引っ越し地獄を引き起こし、パフォーマンスを殺す。
2. 要素数が不明なデータには、圧倒的な効率を誇る `List(Of T)` を採用する。
3. 必要であれば、最後に `.ToArray()` で配列に変換すればよい。

「なんとなく動くコード」から「裏側の仕組みを理解した美しいコード」へ。この視点を持てたあなたは、もうマクロの記録の卒業生を超えて、立派なVB.NETエンジニアの道を歩んでいます。

日々のコーディングを楽しみながら、ぜひ現場でこの知見を活かしてみてくださいね。それでは、また次回の技術でお会いしましょう!

タイトルとURLをコピーしました