1.配列割り当ての上限
Javaの配列のサイズは、Array subscriptとしてINTタイプを使用するため、制限されています。これは、integer.max_value(2^31-1)のサイズを超える配列を適用できないことを意味します。これは、メモリアプリケーションの上限が2gであることを意味するものではありません。さまざまなタイプの配列を申請できます。例えば:
コードコピーは次のとおりです。
final long [] ar = new long [integer.max_value];
これにより、設定した-XMXパラメーターが十分に大きい場合は、16G -8バイトが割り当てられます(通常、スペースの少なくとも50%を保持する必要があります。つまり、16Gのメモリを割り当てる必要があります。単なる一般的なルールであり、特定の配分は実際の状況に依存します)。
残念ながら、Javaでは、配列要素のタイプ制限により、メモリを動作させる方が面倒です。操作アレイに関しては、Bytebufferが最も便利なクラスである必要があります。これは、さまざまなJavaタイプを読み書きする方法を提供します。その欠点は、ターゲット配列タイプがバイト[]である必要があることです。つまり、割り当てた最大メモリキャッシュは2gになる可能性があります。
2。すべての配列をバイト配列として使用して動作させます
2Gメモリが今では十分ではないと仮定すると、16Gの場合は問題ありません。長い[]を割り当てましたが、バイト配列として操作したいと考えています。 Javaでは、Cプログラマーからsun.misc.unsafeから助けを求めなければなりません。このクラスには、GETN(オブジェクト、オフセット)の2つのメソッドがあります。この方法は、オブジェクトのオフセットがオフセットされ、そのタイプを表す位置から指定されたタイプを取得することですputn(オブジェクト、オフセット、値)メソッドは、オブジェクトのオフセットの位置に値を書き込むことです。
残念ながら、これらのメソッドは、特定のタイプの値のみを取得または設定できます。配列からデータをコピーすると、安全でない別の方法、Copymemory(Srcobject、Srcoffset、DestObject、Destoffet、Count)も必要です。これはSystem.ArrayCopyと同様に機能しますが、配列要素ではなくバイトをコピーします。
sun.misc.unsafeを介して配列のデータにアクセスするには、2つのことが必要です。
1.配列オブジェクトのデータのオフセット
2。配列データのコピーされた要素のオフセット
他のJavaオブジェクトと同様に、配列には実際のデータの前に保存されているオブジェクトヘッダーがあります。このヘッダーの長さは、unsafe.arraybaseoffset(t []。クラス)メソッドによって取得できます。ここで、tは配列要素のタイプです。配列要素のサイズは、unsafe.arrayindexscale(t []。クラス)メソッドを介して取得できます。これは、タイプtのn番目の要素にアクセスする場合、オフセットオフセットはarrayoffset+n*arrayscaleであることを意味します。
簡単な例を書きましょう。長い配列を割り当て、内部の数バイトを更新します。最後の要素を-1(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffに更新し、この要素のすべてのバイトを1つずつクリアします。
コードコピーは次のとおりです。
final long [] ar = new long [1000];
final int index = ar.length -1;
ar [index] = -1; // fffffffff
System.out.println( "before change =" + long.tohexstring(ar [index]));
for(long i = 0; i <8; ++ i)
{
unsafe.putbyte(ar、longarrayoffset + 8l * index + i、(byte)0);
System.out.println( "変更後:i =" + i + "、val =" + long.tohexstring(ar [index]));
}
上記の例を実行する場合は、次の静的コードブロックをテストクラスに追加する必要があります。
コードコピーは次のとおりです。
プライベート静的ファイナル安全でない安全でない。
静的
{
試す
{
フィールドフィールド= unsafe.class.getDeclaredfield( "theunsafe");
field.setAccessible(true);
unsafe =(unsafe)field.get(null);
}
キャッチ(例外e)
{
新しいruntimeexception(e);
}
}
private static final long longarrayoffset = unsafe.arraybaseoffset(long []。クラス);
出力の結果は次のとおりです。
コードコピーは次のとおりです。
変更前= fffffffffffffffffff
変更後:i = 0、val = ffffffffffffff00
変更後:i = 1、val = fffffffffffff0000
変更後:i = 2、val = fffffffffff000000
変更後:i = 3、val = fffffffff00000000
変更後:i = 4、val = ffffff00000000000
変更後:i = 5、val = ffff0000000000000
変更後:i = 6、val = ff000000000000000
変更後:i = 7、val = 0
3。sun.misc.unsafeのメモリ割り当て
上記のように、純粋なJavaでは、割り当てることができるメモリサイズは限られています。この制限はJavaの初期バージョンで設定されており、その時、人々はこのようないくつかのgの記憶をあえて共有しませんでした。しかし、今ではビッグデータの時代であり、より多くの記憶が必要です。 Javaでは、より多くのメモリを取得する2つの方法があります。
1.メモリの多くの小さな塊を割り当ててから、記憶の連続的な大きな塊として論理的に使用します。
2. sun.misc.unsafe.allcatememory(long)を使用して、メモリを割り当てます。
最初の方法は、アルゴリズムの観点から少し興味深いので、2番目の方法を見てみましょう。
sun.misc.unsafeは、メモリを割り当て、再アロークする、および放出する一連のメソッドを提供します。それらは、CのMalloc/Free Methodに非常に似ています。
1.LONG UNSAFE.ALLOCATEMEMEMORY(Long Size) - メモリ空間を挿入します。このメモリには、ジャンクデータが含まれている場合があります(自動的にクリアされていません)。割り当てが失敗した場合、java.lang.outofmemoryerrorの例外がスローされます。ゼロ以外のメモリアドレスを返します(以下の説明を参照)。
2.Unsafe.RealLocateMemomory(長いアドレス、長いサイズ) - 新しく割り当てられたメモリブロックを古いメモリバッファー(アドレスが指す)からメモリをリアル化し、データをコピーします。アドレスが0に等しい場合、この方法はAllocateMemoryと同じ効果があります。新しいメモリバッファーのアドレスを返します。
3.Unsafe.Freememory(Long Address) - 前の2つの方法によって生成されたメモリバッファーを含まない。アドレスが0の場合、何もしません。
これらのメソッドによって割り当てられたメモリは、単一のレジスタアドレスと呼ばれるモードで使用する必要があります。UNSAFEは、1つのアドレスパラメーターのみを受け入れる一連のメソッドを提供します(デュアルレジスタモードとは異なり、オブジェクトとオフセットオフセットが必要です)。この方法で割り当てられたメモリは、-XMXのJavaパラメーターで構成するものよりも大きくなります。
注:Unsafeによって割り当てられたメモリは、収集するごみにすることはできません。通常のリソースとして扱い、自分で管理する必要があります。
以下は、Unsafe.AllocateMemoryを使用してメモリを割り当てる例を示します。また、メモリバッファー全体が読みやすく書くことができるかどうかを確認します。
コードコピーは次のとおりです。
final int size = integer.max_value / 2;
最終的な長いaddr = unsafe.allocatememory(size);
試す
{
System.out.println( "Unsafe address =" + addr);
for(int i = 0; i <size; ++ i)
{
unsafe.putbyte(addr + i、(byte)123);
if(unsafe.getByte(addr + i)!= 123)
system.out.println( "offset =" + i)で失敗しました);
}
}
ついに
{
unsafe.freememory(addr);
}
ご覧のとおり、sun.misc.unsafeを使用して、非常に一般的なメモリアクセスコードを記述できます。どのような種類のメモリが割り当てられていても、あらゆる種類のデータを自由に読み書きできます。