26

利用可能なRAMの割合を使用して、Javaでオブジェクトをキャッシュする必要があります。他の人がこの質問をしたことは承知していますが、どの回答も私の要件を満たしていません。

私の要件は次のとおりです。

  • シンプルで軽量
  • プレーンな HashMap よりも劇的に遅くない
  • LRU、または LRU に近い削除ポリシーを使用する

LinkedHashMap を試してみましたが、要素の最大数を指定する必要があり、使用可能な RAM をいっぱいにするのに必要な要素の数がわかりません (サイズは大きく異なります)。

私の現在のアプローチは、Google コレクションの MapMaker を次のように使用することです。

Map<String, Object> cache = new MapMaker().softKeys().makeMap();

これは、より多くの RAM が必要なときに要素を自動的に削除する必要があるため、魅力的に思えましたが、重大な問題があります。その動作は、利用可能なすべての RAM をいっぱいにすることであり、その時点で GC がスラッシングし始め、アプリ全体のパフォーマンスが劇的に低下します。

EHCache のようなものについて聞いたことがありますが、必要なものに対して非常に重いようで、アプリケーションにとって十分に高速かどうかはわかりません (ソリューションが HashMap よりも劇的に遅くなることはあり得ないことを思い出してください)。 .

4

12 に答える 12

8

私はあなたと同様の要件を持っています - 並行性 (2 つのヘキサコア CPU 上) と LRU など - そして Guava MapMaker も試しました。softValues() は weakValues() よりもはるかに遅いことがわかりましたが、どちらもメモリがいっぱいになるとアプリが非常に遅くなりました。

私は WeakHashMap を試してみましたが、問題が少なく、奇妙なことに、LinkedHashMap を removeEldestEntry() メソッドを介して LRU キャッシュとして使用するよりも高速でした。

しかし、私にとって最も速いのはConcurrentLinkedHashMapで、これにより、私が試した他のどのキャッシュよりもアプリが 3 ~ 4 (!!) 倍速くなりました。喜び、フラストレーションの日々の後!どうやら Guava の MapMaker に組み込まれているようですが、LRU 機能はいずれにしても Guava r07 にはありません。それがうまくいくことを願っています。

于 2010-10-04T00:17:47.533 に答える
4

サーバーキャッシュを実装しましたが、おそらく新しいデータソースまたはスレッドプールを実装するのと同じくらい難しいでしょう.jboss-cacheまたは別のよく知られているキャッシュライブラリを使用することをお勧めします. だから問題なくぐっすり眠れます

于 2010-01-29T00:27:07.093 に答える
3

EHCache のようなものについて聞いたことがありますが、必要なものに対して非常に重いようで、アプリケーションにとって十分に高速かどうかはわかりません (ソリューションが HashMap よりも劇的に遅くなることはあり得ないことを思い出してください)。 .

EHCacheが重いと言えるかどうかは本当にわかりません。少なくとも、私は EHCache をそのようには考えていません。特にメモリ ストアを使用している場合はそうです (これは拡張によってサポートされてLinkedHashMapおり、もちろん最速のキャッシュ オプションです)。試してみてください。

于 2010-01-29T08:13:57.140 に答える
2

MapMakerあなたが求めているものを手に入れるための唯一の合理的な方法になると私は信じています。「GC がスラッシングし始め、アプリ全体のパフォーマンスが劇的に低下する」場合は、さまざまな調整パラメーターを適切に設定するために時間を費やす必要があります。このドキュメントは最初は少し難解に思えるかもしれませんが、実際には非常に明確に書かれており、GC に関する有益な情報の宝庫です。

https://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf

于 2010-01-29T19:32:29.457 に答える
1

これが、特にEHCacheなどと比較して、単純な解決策になるかどうかはわかりませんが、Javolutionライブラリを見たことがありますか?そのように設計されていませんが、javolution.contextパッケージには、ガベージコレクションを必要とせずにオブジェクトを再利用できるアロケータパターンがあります。このようにして、オブジェクトの作成とガベージコレクションを最小限に抑えます。これは、リアルタイムプログラミングの重要な機能です。おそらく、あなたはそれを見て、あなたの問題に適応させようとするべきです。

于 2010-01-29T09:35:38.767 に答える
0

何かをキャッシュする、SoftReferenceおそらく今まで私が想像できる最善の方法。

または、オブジェクトプールを再発明することもできます。使用しないすべてのオブジェクトを破棄する必要はありません。しかし、それはメモリを節約するのではなく、CPUを節約するためです

于 2012-03-23T03:55:07.980 に答える
0

Javaでオブジェクトのサイズを見つける簡単な方法を知りません。したがって、使用するRAMの量によってデータ構造を制限する方法はないと思います。

この仮定に基づいて、キャッシュされたオブジェクトの数によって制限することに固執しています。いくつかの実際の使用シナリオのシミュレーションを実行し、キャッシュに入るオブジェクトのタイプに関する統計を収集することをお勧めします。次に、統計的に平均的なサイズと、キャッシュできるオブジェクトの数を計算できます。これは、キャッシュ専用にするRAMの量の概算にすぎませんが、十分な場合があります。

キャッシュの実装に関しては、私のプロジェクト(パフォーマンスが重要なアプリケーション)ではEhCacheを使用していますが、個人的にはEhCacheが重いとはまったく感じていません。

いずれにせよ、いくつかの異なる構成(サイズ、エビクションポリシーなど)でいくつかのテストを実行し、最適なものを見つけてください。

于 2010-01-29T07:22:16.860 に答える
0

これは、より多くの RAM が必要な場合に要素を自動的に削除する必要があるため、魅力的に思えましたが、深刻な問題があります。その動作は、利用可能なすべての RAM をいっぱいにすることです。

ソフト キーを使用すると、ガベージ コレクターは、他のオブジェクトがそれらを参照していない場合 (つまり、キャッシュ キーを参照しているのはキャッシュ自体のみである場合) にオブジェクトをキャッシュから削除できます。他の種類の追放を保証するものではありません。

あなたが見つけたほとんどの解決策は、EhCache を含む Java Map クラスの上に追加された機能です。

commons-collections LRUMapを見たことがありますか?

LRU/MRU 機能を提供するために MapMaker に対して未解決の問題があることに注意してください。そこで意見を言ってもいいかもしれません

于 2010-01-28T23:56:45.093 に答える
0

「要素を削除」することはできません。それらをハード参照するために停止し、GC がそれらをクリーンアップするのを待つことしかできないので、Google コレクションに進みます...

于 2010-01-29T07:05:32.037 に答える
0

過去に私はJCSを使用しました。構成をセットアップして、ニーズに合わせて試すことができます。これがすべての要件/ニーズを満たすかどうかはわかりませんが、使用すると非常に強力であることがわかりました.

于 2010-01-29T00:50:20.337 に答える
0

既存のキャッシュを使用して、通常のオブジェクト参照ではなく WeakReference を保存します。

GC で空き容量が不足し始めると、WeakReferences が保持する値が解放されます。

于 2010-01-29T00:03:22.623 に答える
-3

キャッシュをスレッドセーフにしたい場合は、Brian Goetz の著書「Java Concurrency in Practice」のキャッシュの例を調べる必要があります。これはあまりお勧めできません。

于 2010-01-29T00:21:27.360 に答える