4

アプリ(Spring、JPA Hibernate、Sybase 12、Webapp)を起動時にローカルで実行すると、VisualVMに基づく256MBのヒープスペースのうち40MBが消費されます。70,000行以上(テキストデータにブロブなし)を返す検索をトリガーすると、ヒープスペースグラフは最大256MBになり、メモリが不足します。setMaxResults(limit)を使用してこれを解決しました。ただし、同じデータを照会し、テキストファイルにコピーして貼り付けてファイルシステムに保存すると、サイズはわずか26MBのテキストに相当することがわかります。

つまり、実際には、データベースから26MBのテキストをロードすることで216MB(256〜40)が消費されますが、メモリ不足が発生するまでに190MBを消費しているのは誰ですか?おそらくそれはフレームワークでしょうが、ロードされている実際のデータよりも多くを消費する方法がわかりません...

* * setMaxResults(limit)を使用してこれを解決したことに再度注意してください。私の質問は、教育目的で何をするかではなく、なぜかということです。

4

2 に答える 2

5

考慮すべきいくつかの事柄:

お使いのオペレーティングシステムは、おそらく1文字あたり8ビットのエンコーディングを使用してテキストファイルを保存しています。Java文字列は、内部的にすべて1文字あたり16ビットでエンコードされており、スペースが2倍になります。

数桁しかない数字は、数字よりもテキストとして小さくエンコードされます。たとえば、「1」はテキストファイルの1バイト文字ですが、値が1のlongは、メモリ内のそのサイズの8倍です。

SQL結果セットから値を取り出してJavaオブジェクトにマッピングする休止状態からの重複があります。結果セットの内容を、マッピングで定義したタイプにラップ/変換する必要がある場合があります。

エンティティの数が多く、エンティティあたりのデータが実際に小さい場合、データサイズに対するオブジェクトのオーバーヘッドサイズの比率は明らかに高くなります。

コレクションに小さなデータがある場合、コレクションのサイズはデータに比べてすぐに加算される可能性があります。極端な例では、1つまたは2つの文字列のLinkedListがある場合、実際のデータの16〜32ビットごとにポインターによって192ビットが消費されます。配列リストでは、ポインタが16〜32ビットのデータを指すのは64ビットのままです。(もちろん64ビットOSを想定しています。)

Hibernateにロードするすべてのオブジェクトは、L1キャッシュと呼ばれるもののダーティチェックのために「追跡」されます。確かに、少量のデータを持つ多数のエンティティのデータサイズに比べて、これを行うために使用される内部データ構造とインストルメンテーションにはかなりのオーバーヘッドが発生する可能性があります。

-

したがって、26MBのデータは、Javaのメモリ内の52MBのデータであり、すべて文字列、数値、日付がないと仮定すると、それ以外の場合はさらに大きくなります。

そして、1,000個の実際に長い文字列ではなく、700,000個の小さな文字列に分割された場合、データ構造のオーバーヘッドのサイズを実際のデータの3倍にして、200MBを簡単に超えることができます。

于 2012-07-27T03:33:10.613 に答える
2

いろいろなもの。

たとえば、行に10個のテキスト列があり、10個の文字列フィールドを持つ単純なJavaBeanとして表されているとします。

文字列には、char[]と3つのintの4つのフィールドがあります。

文字列は、1つのintとそのクラスへの参照を持つObjectの子孫です。

64ビットJVMでは、これらの参照は8バイトになる可能性があります(ただし、必ずしもそうとは限りませんが、議論のためにこれを使用します)。

10文字の文字列には、char [10]と、それぞれ4バイトの3つのintが含まれます。

char[10]は配列へのポインタです。配列はその長さを追跡する必要があります。これはおそらくさらに4バイトであり、オブジェクト(したがって、クラスポインターと別のint)とデータでもあります。ただし、Javaの文字は、内部ではUTF-16として表され、1文字あたり2バイトです。したがって、10文字の実際の配列は24バイトを使用します。そして、その配列への参照はポインターです。

したがって、単一の文字列インスタンスは、オブジェクトの場合は8 + 4、文字列自体の場合は8 + 4 + 4 + 4、実際のデータの場合は8 + 4 + 20、つまり62バイトです。

Beanには10個のStringフィールドがあり、さらにObjectを拡張するため、8 + 4 +(10 * 8)になります。

したがって、100文字のテキストに対するデータベースの1行は、8 + 4 +(10 * 8)+(10 * 62)であり、これは712バイトに相当します。

これらは完全数ではありません。配列がどのように格納されるかについて具体的に話すことはできません。また、オブジェクト参照は64bJVMでは8バイトではない可能性があります。

しかし、それはあなたに関係するオーバーヘッドのいくらかの考えを与えます。そして、これはあなたの生データのためだけです。これらの行をArrayListに格納している場合は、オブジェクトを指すためだけに70,000*8があります。構造だけでは560Kです。

于 2012-07-27T03:45:55.277 に答える