6

解決策が見つからない問題が発生しました。値を格納するために HashSet を使用しています。私が保存する値はカスタムタイプのCyclesであり、HashCodeとequalsを次のようにオーバーライドして、パフォーマンスの低下がhascodeまたはequalメソッドによって引き起こされていないことを確認しますまた、ハッシュセットの初期容量を10.000に設定しました.000

@Override
public int hashCode() {
 final int prime = 31;
 int result = 1;
 result = prime * result + (int) (cycleId ^ (cycleId >>> 32));
 return result;
}

@Override
public boolean equals(Object obj) {
 if (this == obj)
 return true;
 if (obj == null)
 return false;
 if (getClass() != obj.getClass())
 return false;
 Cycle other = (Cycle) obj;
 if (cycleId != other.cycleId)
 return false;
 return true;
}

(HashSet クラスの add メソッドを使用して) 新しい値を追加しようとすると、最初の 1.500.000 の最初の値の後、プログラムは非常に遅くなります。最終的に、格納された値が 1.600.000 に達する前に、Java のメモリ不足例外 (スレッド "Thread-0" java.lang.OutOfMemoryError: Java ヒープ領域の例外) が発生します。

私が使用するIDEはEclipseです。したがって、次のステップは、JVM ヒープ サイズをデフォルト値から 1 ギガに増やすことでした (コマンド Xmx1000M および Xms1000M を使用)。これで、楕円が 10 倍のメモリを使用して開始されます (右下で合計ヒープ サイズが表示されていることがわかります)。メモリと使用済みメモリが表示されます)が、以前と同じ「遅い」パフォーマンスと同じ値のメモリ不足エラー(1.500.000の後と1.600.000の前)があり、非常に奇妙です。

誰がそれが問題である可能性があるか考えていますか?

前もって感謝します

4

9 に答える 9

10

Eclipse の JVM ヒープを増やすのではなく、プログラムに設定したい。

[実行] > [実行構成] (または[デバッグ構成]) に移動し、そこでVM オプションを設定します。

于 2010-07-25T12:56:06.100 に答える
4

十分なヒープ メモリがありません (-Xmx などで増やします-Xmx512m)。空きメモリが非常に少なくなると、ヒープを猛烈にスキャンして到達できないオブジェクトを探すガベージ コレクタによって、非常に多くの時間が費やされます。

hashCode() は問題ありません。longのすべてのビットを使用するための余分なポイントですcycleId

編集します。今、あなたがメモリを増やしたのを見ましたが、役に立ちませんでした。まず第一に、本当にメモリを増やすことができましたか? jconsole でこれを確認し、アプリに接続してヒープ サイズを確認できます。

cycleId別の説明を検証するために、この hashCode() 実装を悪くする可能性のある特定のパターンはありますか? 同様に、上位 32 ビットは下位 32 ビットとほとんど同じです。(そうだね)。

しかし、いいえ。その場合でも、特定のポイントで急激に低下するのではなく、パフォーマンスが徐々に低下することがわかります (そして、OutOfMemoryError と熱狂的な gc 操作が発生します)。したがって、私の最善の推測は、まだメモリの問題です。思ったようにヒープ サイズを増やしていないか、ある時点で他のコードがメモリを取得しています。(VisualVM のようなツールを使用してこれをプロファイリングし、OOME でヒープ ダンプを取得して、そこに含まれるオブジェクトを確認できます)。

Edit2上記の正しい部分を太字にしました。

于 2010-07-25T12:22:44.477 に答える
2

Eclipse から起動するアプリケーションで使用可能なメモリ サイズは、[実行] メニューから設定する必要があります。試す:

実行 -> 実行構成 -> 引数 -> VM 引数 -> -Xmx1000M

あなたのプログラムが遅い理由はガベージ コレクターです。メモリが限界を超えるたびにガベージ コレクターが起動します。

于 2010-07-25T11:59:20.583 に答える
2

hashCodeメソッドの実装をテストしましたか? 31の任意の値に対して、常に を返しますcircleId。HashMap の動作が遅いのは不思議ではなく、線形のパフォーマンスです。

于 2010-07-25T12:02:46.157 に答える
1

プログラムが使用できるメモリを増やしたい場合、Eclipse のヒープ サイズを増やしても役に立ちません。このパラメーターは、プログラムの起動構成の vm パラメーターに入れる必要があります。

于 2010-07-25T12:01:35.847 に答える
1

JVM は、使用可能なメモリに基づいてではなく、「メモリ不足」をスローします。ガベージ コレクションに時間がかかりすぎる場合にスローされます。これを確認してください。正確な実装の詳細は、JVM およびガベージ コレクターの実装によって異なります。

この場合、メモリを増やしても役に立ちません。別のアプローチを選択する必要があるかもしれません。

于 2010-07-25T12:09:05.680 に答える
0

コンピューターのメモリが不足している可能性があるため、ディスクにスワップする必要があります。

于 2010-07-25T11:54:16.070 に答える
0

どのように初期化していますHashSetか? その成長パターンに注意する必要があります。すべてのadd操作で、容量に近づいているかどうかを確認します。特定のポイント(「負荷係数」によって決定される)に達すると、コストがかかる可能性のあるサイズ変更操作を実行します。JavaDoc から (of HashMap- backs コレクションHashSet):

原則として、デフォルトの負荷係数 (.75) は、時間とスペースのコストの間の適切なトレードオフを提供します。値を大きくすると、領域のオーバーヘッドは減少しますが、ルックアップ コストが増加します (get と put を含む HashMap クラスのほとんどの操作に反映されます)。再ハッシュ操作の回数を最小限に抑えるために、初期容量を設定するときは、マップ内の予想エントリ数とその負荷係数を考慮する必要があります。初期容量がエントリの最大数を負荷係数で割った値よりも大きい場合、再ハッシュ操作は発生しません。

于 2010-07-25T12:36:14.783 に答える