1

我正在创建一个必须处理很多点的 java 程序。当我说很多时,我指的是超过 100,000 点。此外,我将不得不一遍又一遍地创建点。我担心这个对象创建会减慢我的算法时间,并占用大量内存。

我想出了几个可能的解决方案,这些可行吗?有没有更好的方法来处理这种情况?

解决方案 1) -A 点“工厂”,所有点都被发送到该点而不是被销毁。在这里,它们将被回收,因此我们不必重新创建对象。

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

如果构造一个只有两个整数的对象所花费的时间对您的应用程序造成了影响,我会感到惊讶。我敢打赌,维护对象池或工厂的开销会产生类似的开销,但这需要进行分析。但是,如果您发现这是一个问题,请查看构建对象池

于 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 版本中,对象的分配比以往任何时候都快得多,并且池化实际上会降低性能(除了在非常特殊的情况下,例如数据库池化),原因有多种,例如太大的池会影响 GC一个不好的方法,但是太小什么也不能提供,当对象没有正确返回到池时会出现细微的错误等。多线程应用程序中的性能更差,因为由于不实例化新对象并重用缓存的对象,因此必须有人阻塞等。
在阅读之前,我一直认为推荐的做法是使用对象池。
读完这本书后发现它实际上是一种反模式(如果不用于确实证明很昂贵的话对象)。
因此,只需根据需要使用普通旧的对象分配对象,new并且如果您的对象分配确实被证明是昂贵的(通过分析等),那么开始研究池和缓存策略。

@Jeffrey 恕我直言的推荐显示了一种很好的方法来开始调查您的对象是否真的很昂贵。这是一个起点。

于 2012-08-21T22:30:43.537 回答
1

我做过很多处理数百万个对象的项目,实例化对象从来都不是主要的性能问题。

一旦您进行 IO,例如从数据库读取或读取文件,创建新对象看起来会非常非常快。

于 2012-08-21T22:19:31.170 回答
1

XY 结构实际上只是对您点的数据成员的巧妙重命名。除了将数据放在错误的类中(并为开销创建第二类)之外,它不会为您购买任何额外的东西。

相比之下,工厂方法将节省您分配重复点(如 0,0)的需要,如果您已经分配了它们。如果您收到对 0,0 的后续请求,您可以缓存这些点并从缓存中返回相同的点。

根据您构建工厂的方式,您甚至可以回收您的点并“回收它们”,这意味着“重置它们的 x 和 y 坐标,在第二次“使用”中返回相同的对象。但是,这种技术通常不受欢迎之后,就好像您在重置 X 和 Y 值之前无法验证某个点是否不可到达一样,您通常会在程序中引入不需要的行为。

无论如何,我不建议在工厂发布这些点后将它们“更新”;因为,如果它们是,那么将点身份管理包装在工厂类中的整个能力变得如此复杂,可能不值得。

于 2012-08-21T22:19:41.763 回答
0

您似乎正在重新发明Object Pool,如果您确实需要它,这是完全合理的。

但是如果你使用它,你可能应该阅读这个模式并适当地命名它。“工厂”已经用于太多事情了。

于 2012-08-21T22:22:37.810 回答