TS工房 -技術者と研究者とモノづくり-

音楽や芸術のスタジオやアトリエの様な雰囲気の工房で、研究者として・技術者として”ものづくり”をしたい

MENU

【LabVIEW】大容量バイナリファイルを読み込んだらメモリがいっぱいですエラー

現在進行中の悩みです。。

二週間くらいかけて完成させたLabVIEWプログラムだったのですが、使いだしてみると大小さまざまなバグや修正箇所がたくさん出てきます。このうちバグの一つが、題名のとおり「大容量バイナリファイルを読み込んだらメモリがいっぱいです」のエラーです。

f:id:wannavi:20210113001034j:plain

メモリエラー

メモリ管理や実行速度を意識して組んでいたつもりだったのですが、想定よりも重いファイルではテストをしていなかったため最後まで気づきませんでした。ちなみに当初の想定では、バイナリファイルのファイルサイズは最大100MBで、エラーを起こした際のファイルサイズは250MBでした。

プログラムを調べてみると、原因は「割り算による自動型変換」でした。下の図がやらかした部分の例です。

f:id:wannavi:20210112235727p:plain

自動で型変換されてしまう

大容量ファイルの中身は16bit配列なのですが、途中割り算をすることでオレンジ色の線に示す64bit配列になっています。無駄なメモリを消費しないために再び型変換をして16bit配列に抑えていました。ここでメモリエラーを起こしていたのは、オレンジ色の64bit配列になっている部分です。LabVIEWのプログラム上で線こそは短いですが、250MB(16bit)のファイル(配列)を64bitの精度で読み直していることから、オレンジ色の線の部分は1GBの連続メモリを要求していることになるわけですね。これではエラーを起こすのも無理ないでしょう。

そこで大容量ファイルの読み取り部分を考え直す必要があるという結論に至りました。プログラムを修正する前に、そもそもLabVIEWで扱えるデータサイズなどが気になったため、以下にメモしておきます。

LabVIEWで扱えるデータサイズはどれくらいまでか

ちゃんとNIの公式ページに記載がありました。以下は、「どのくらいのメモリをLabVIEW 32ビットまたは64ビットに割り当てることができますか?」からの引用です。

LabVIEWが使用できるメモリ容量は、使用しているバージョンとオペレーティングシステムによって異なります。

LabVIEW (32-bit)

32ビットWindowsオペレーティングシステムでは、LabVIEWはデフォルトで最大2 GBの仮想メモリにアクセスできます。 ただし、これはブート構成データストアを変更することで3 GBまで拡張できます。

64ビットWindowsオペレーティングシステムでは、LabVIEWは変更なしで最大4 GBの仮想メモリにアクセスできます。

LabVIEW (64-bit)

Windows Vista(64ビット)、Windows 7(64ビット)、Windows 8(64ビット)、およびWindows 10(64ビット)でLabVIEW 2009(64ビット)以降を使用する場合、LabVIEWは最大16 TBの仮想メモリを使用できます。

 

ちょっとした感想

C言語のようなテキストベースのプログラミング言語では、メモリ管理がとても重要です。逆に言えば、いちいちプログラマがメモリを気にしてあげないといけません。メモリを使用する前にメモリを割り当て、メモリの使用を終了したらメモリを開放してと。。。

LabVIEWMATLABでもそうなのですがこれらの言語では、新しい情報を管理するために十分なメモリが自動的に割り当てられる、つまりメモリ管理をあまり意識しなくて良いというのがメリットだなと思っていました。

ただ今回のようなメモリエラーに直面すると、自動処理であるがためのデメリットもあるのだなと感じます。明日以降、大容量ファイルの読み取り部分を考え直すこととしていますので、良い方法が見つかればこの場でご報告をしたいと思います。

【LabVIEW】二次元配列(二次元強度分布)のサイズを変更するプログラム

まさに今日悩んでいたのがコレ。なにがやりたかったかというと、例えば16pixel×16pixel二次元強度マップを、4pixel×4pixelにサイズを変更したいというもの。下の図が分かりやすいと思う。

f:id:wannavi:20210105231802p:plain

こんな感じで二次元強度分布のサイズを変更したかった

もともとの左上の4×4の部分を一個のピクセルに代表して表示させたかったというもの。Google検索しようにもキーワードが思い浮かばなかったのですが、これは何という処理なのだろう。リサイズ?ビニング?圧縮??? 正解をご存知の方がいたらコメントで教えてください。

サンプルプログラム

C言語であれば迷わず二重Forループで組むのですが、正直LabVIEWで二重ループを組んでIf文の条件式を組み合わせると頭が混乱します。そのため、頭が混乱しないような形でプログラミングできないあかと試行錯誤した結果が、以下のサンプルプログラムです。VIスニペットにしていますので、もし使いたいという方は自由に利用してください。

f:id:wannavi:20210105231846p:plain

Sample Program

f:id:wannavi:20210105231906p:plain

Output

サンプルプログラムについて少しだけ説明をしておきます。一番左のForループは16×16の二次元配列を生成しているだけです。中段と後段のForループが試行錯誤したところです。「デシメート1D配列」と「2D配列転置」を使っているのがポイントだと思っています。一度に16pixel×16pixelを4pixel×4pixelに変更することが難しいため、まず中段のForループで16×4pixelにし、さらに後段のForループで4pixel×4pixelに変更しています。

中段のForループには16×16の二次元配列が配線されています。Forループの規則性から、一行(一次元配列)ごとループの中で処理されていきます。Forループと配列の処理規則について(?)と思った方は、前回の「Forループを使って配列の個別要素を処理する。次元を落とす感覚」を一緒に確認してください。一次元配列をデシメート1D配列を使って、先頭から順に4つの一次元配列に詰めていきます。

デシメート1D配列のイメージとしては、「1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16」を要素4でデシメートすると以下のようになります。

  • 1,5,9,13
  • 2,6,10,14
  • 3,7,11,15
  • 4,8,12,16

それを内側のForループでサンプルプログラムのように足し合わせると「1+2+3+4」「5+6+7+8」「9+10+11+12」「13+14+15+16」となります。Forループの出口で連結されるため、外側のループを抜けるときには再び二次元配列に戻り、16×4pixelになります。同様に後段のForループも計算していますが、列方向を圧縮したいため転置をしています。当然ながら最終段では再度転置をして戻します。

このプログラムの欠点は、4k*4kを128*128に直したい場合、デシメートを32にしないといけないため配線するのが大変です。また、縦方向と横方向を任意に変更できないというのも痛いところです。作り終わってから思ったのは、C言語でパッと思いつく二重Forループ構文で書いた方が、後々の汎用性はあったなということです。ちょっと反省。