1

多くのポイントを処理する必要がある Java プログラムを作成しています。よく言えば10万ポイント以上。さらに、ポイントを何度も作成する必要があります。このオブジェクトの作成によってアルゴリズムの時間が遅くなり、大量のメモリが消費されるのではないかと心配しています。

考えられる解決策はいくつかありますが、これらは機能しますか? 状況を処理するためのより良い方法はありますか?

解決策 1) -すべてのポイントが破壊される代わりに送信されるポイント「工場」。ここでは、それらはリサイクルされるため、オブジェクトを再作成する必要はありません。

public class PointFactory {

public final static List<Point> unused = new ArrayList<Point>();


public static void disposePoint( Point point ){
    unused.add( point );

}

public static void disposePoints( List<Point> points ){

    for( Point point: points )
        unused.add( point );

}


public static Point newPoint( int x, int y ){

    if( unused.isEmpty() )
        return new Point( x, y );
    else{

        Point point = unused.get(0);

        point.x = x;
        point.y = y;

        return point;

    }

}

}

解決策 2) 解決策 1 と非常に似ていますが、不要なオーバーヘッドを避けるために新しい構造 "XY" を使用します。必要なのは X 値と Y 値だけです。

public class XYFactory {

public final static List<XY> unused = new ArrayList<XY>();



public static void disposeXY( XY xy ){
    unused.add( xy );

}

public static XY newXY( int x, int y ){

    if( unused.isEmpty() )
        return new XY( x, y );
    else{

        XY xy = unused.get(0);

        xy.x = x;
        xy.y = y;

        return xy;

    }

}

}

public class XY {

public XY( int x, int y ){
    this.x = x;
    this.y = y;

}

public int x;
public int y;

public boolean equals( Object o ){

    if( !( o instanceof XY ) )
        return false;

    XY xy = (XY)o;

    return xy.x == x && xy.y == y;

}

}

4

6 に答える 6

2

たった 2 つの int を持つオブジェクトを構築するのにかかる時間が、アプリケーションに負担をかけているとしたら、私は驚かれることでしょう。実装したオブジェクト プールまたはファクトリを維持するオーバーヘッドは、同様のオーバーヘッドが発生するに違いありませんが、これはプロファイリングする必要があります。ただし、これが問題であることがわかった場合は、オブジェクト プールの構築を検討してください。

于 2012-08-21T22:19:50.220 に答える
2

これは時期尚早の最適化のように聞こえます。アルゴリズムを実際に実装したときに、オブジェクトの作成が原因でパフォーマンスが大幅に低下していることに気付いた場合は、事前にではなく、このようなことについて考え始める必要があります。

の各インスタンスはjava.awt.Point、最大 16 バイトのメモリを消費します。

  • int x= 4 バイト
  • int y= 4 バイト
  • オブジェクトのオーバーヘッド = 8 バイト

100,000Point秒 = 1,600,000 バイト = 1.52 MB

于 2012-08-21T22:21:23.690 に答える
2

ただ明確にします。これは私の個人的な意見ではなく、Brian Goetz (Bloch、Lea など) によるものです。Java Concurrency In Practice

おすすめはDon't do object pooling.

これらの専門家によると、オブジェクトの割り当ては、最近の JVM エディションではこれまでになく大幅に高速化されており、プーリングは、さまざまな理由 (データベース プーリングなどの非常に特殊なケースを除く) でパフォーマンスを低下させることが実際に示されています。悪い方法ですが、小さすぎると何も提供されず、オブジェクトがプールに適切に返されない場合の微妙なバグなどがあります。新しいオブジェクトをインスタンス化せず、キャッシュされたオブジェクトを再利用することにより、誰かがブロックする必要があるため、マルチスレッドアプリケーションのパフォーマンスが低下します。
これについて読む前に、推奨されるアプローチはオブジェクトプールを使用することだと常に思っていました。
本を読んだ後、それは実際にはアンチパターンであることが判明しました(実際に使用されていない場合-証明された高価なオブジェクト)。
したがって、単純な古いものを使用して必要に応じてオブジェクトを割り当てるだけでnew、オブジェクトの割り当てが実際に高価であることが証明されている場合(プロファイリングなどによって)、プーリングとキャッシュの戦略を調べ始めます。

@Jeffrey IMHO による推奨事項は、オブジェクトが本当に高価かどうかの調査を開始するための優れたアプローチを示しています。出発点です。

于 2012-08-21T22:30:43.537 に答える
1

私は何百万ものオブジェクトを扱う多くのプロジェクトを行ってきましたが、オブジェクトのインスタンス化がパフォーマンスの主な問題になることはありませんでした。

データベースからの読み取りやファイルの読み取りなど、IO を作成するとすぐに、新しいオブジェクトの作成は非常に高速に見えます。

于 2012-08-21T22:19:31.170 に答える
1

XY 構造は、実際には、ポイントのデータ メンバーを巧妙に名前変更しただけです。データを間違ったクラスに入れる (そしてオーバーヘッドのために 2 番目のクラスを作成する) 以外に、余分なものは何もありません。

対照的に、ファクトリ メソッドでは、重複するポイント (0,0 など) を既に割り当てている場合に割り当てる必要がなくなります。ポイントをキャッシュし、その後 0,0 のリクエストを受け取った場合、キャッシュから同じポイントを返すことができます。

ファクトリの構造によっては、ポイントを再利用して「リサイクル」することもできます。つまり、「x 座標と y 座標をリセットし、2 回目の使用」で同じオブジェクトを返すことを意味します。ただし、このような手法は一般的に眉をひそめられます。 X 値と Y 値をリセットする前にポイントに到達できないことを確認する手段がないかのように、通常、プログラムに望ましくない動作が発生します。

いずれにせよ、工場がリリースした後にポイントを「更新可能」にすることはお勧めしません。もしそうなら、ファクトリ クラス内にポイント アイデンティティ管理をラップする機能全体が非常に複雑になり、おそらく価値がないからです。

于 2012-08-21T22:19:41.763 に答える
0

Object Poolをほぼ再発明しているようです。これは、実際に必要な場合に完全に合理的です。

ただし、このパターンをよく読んで、使用する場合は適切な名前を付ける必要があります。「工場」はすでにあまりにも多くのものに使用されています。

于 2012-08-21T22:22:37.810 に答える