gonypage diary

トップ > 2021/10 > 17

2021/10/17

18:39 .NETのbyte[]で確保できる領域は2GB弱まで

Qtベースの医療画像処理アプリケーションを開発しているが、Looking GlassなどのUnity SDKを使用する立体視デバイスに対応するためにUnityベースのコンパニオンアプリケーションを用意し、そちらにネットワーク経由でデータを送信することで連携を実現しようとしている。

すでに基本的な動作はできているのだが、3000枚程度のCTデータを送信すると正しく動作しないことがわかり、問題を調査したところデータサイズが2GBを超える場合にUnity側で受信用のバッファの確保に失敗しているらしいということがわかってきた。

調べてみると.NETのドキュメントにbyteとサイズが1バイトの構造体のArrayのサイズは2147483591(0x7FFFFFC7)まで、それ以外はArrayのサイズは2146435071(0x7FEFFFFF)まで、という記述を見つけた。だとするとbyte[]を使用して2GB超のバッファを確保することはできないということになる。それは困る。

困るので確認のために以下のテストコードを書いた:

using System;

namespace TestByteArray
{
    class Program
    {
        public static void Main(string[] args)
        {
            TestAllocation(0x7FEFFFFFl);
            TestAllocation(0x7FF00000l);
            TestAllocation(0x7FFF0000l);
            TestAllocation(0x7FFFF000l);
            TestAllocation(0x7FFFFF00l);
            TestAllocation(0x7FFFFFC7l);
            TestAllocation(0x7FFFFFC8l);
            TestAllocation(0x7FFFFFF0l);
            TestAllocation(0x7FFFFFFFl);
            TestAllocation(0x80000000l);
        }

        private static void TestAllocation(long size)
        {
            Console.Write("Trying to allocate {0}(0x{0:X}) bytes...\n", size);
            try
            {
                var buffer = new byte[size];
                Console.Write("Succeeded.\n");
            }
            catch (Exception e)
            {
                Console.Write("Failed. Thrown exception:\n");
                Console.Write("{0}\n", e.ToString());
            }
            Console.Write("\n");
        }
    }
}

出力結果は以下の通り:

Trying to allocate 2146435071(0x7FEFFFFF) bytes...
Succeeded.

Trying to allocate 2146435072(0x7FF00000) bytes...
Succeeded.

Trying to allocate 2147418112(0x7FFF0000) bytes...
Succeeded.

Trying to allocate 2147479552(0x7FFFF000) bytes...
Succeeded.

Trying to allocate 2147483392(0x7FFFFF00) bytes...
Succeeded.

Trying to allocate 2147483591(0x7FFFFFC7) bytes...
Succeeded.

Trying to allocate 2147483592(0x7FFFFFC8) bytes...
Failed. Thrown exception:
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at TestByteArray.Program.TestAllocation(Int64 size) in C:\Users\gony\Documents\TestByteArray\TestByteArray\Program.cs:line 31

Trying to allocate 2147483632(0x7FFFFFF0) bytes...
Failed. Thrown exception:
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at TestByteArray.Program.TestAllocation(Int64 size) in C:\Users\gony\Documents\TestByteArray\TestByteArray\Program.cs:line 31

Trying to allocate 2147483647(0x7FFFFFFF) bytes...
Failed. Thrown exception:
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at TestByteArray.Program.TestAllocation(Int64 size) in C:\Users\gony\Documents\TestByteArray\TestByteArray\Program.cs:line 31

Trying to allocate 2147483648(0x80000000) bytes...
Failed. Thrown exception:
System.OverflowException: Array dimensions exceeded supported range.
   at TestByteArray.Program.TestAllocation(Int64 size) in C:\Users\gony\Documents\TestByteArray\TestByteArray\Program.cs:line 31

ドキュメントの通り0x7FFFFFC7バイトまでは確保できていることがわかる。それ以上確保しようとすると例外を投げられるわけだが、0x80000000バイト確保しようとすると飛んでくる例外がOverflowExceptionに変わるところも気になる。これはもしかして確保サイズが暗黙的に符号付き32ビットに変換されていて、負のサイズで確保しようとしているのでは...

扱いたいデータのサイズが2GBを超えるなんてうちの業界ではザラなので大変困る制約である。もう64ビットデータなんてさらっと扱えて当たり前の時代だと思っていたので、こんな制約にハマるとは思ってはいなかった。今はちょっと対策を考えたくないので後回しにする...

Generated by Rui 0.4.1