我正在创建一个必须处理很多点的java程序。当我说了很多,我说的是超过100,000点。此外,我必须一遍又一遍地创造积分。我担心这个对象创建会减慢我的算法时间,并耗尽大块的内存。
我想出了一些可能的解决方案,这些有用吗?有没有更好的方法来处理这种情况?
解决方案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;
}
}
答案 0 :(得分:2)
如果只用两个整数构建一个对象所花费的时间会对你的应用程序产生影响,我会感到惊讶。我敢打赌,维护对象池或工厂的开销会产生类似的开销,但这需要进行分析。但是,如果您发现这是一个问题,请参阅构建Object Pool
答案 1 :(得分:2)
这听起来像是一个不成熟的优化。如果,当你实际实现你的算法时,你会注意到由于对象创建而导致显着的性能下降,那么你应该开始考虑这样的事情,而不是之前。
java.awt.Point
的每个实例将占用大约16个字节的内存:
int x
= 4个字节int y
= 4个字节 100,000 Point
s = 1,600,000字节= 1.52 MB
答案 2 :(得分:2)
要清楚。这不是我个人的意见,来自Java Concurrency In Practice
推荐是Don't do object pooling.
根据这些专家的说法:在最近的JVM版本中,对象的分配比之前的明显更快,并且池实际上已被证明会降低性能(除非由于各种原因,例如,特定情况,例如数据库池)太大的池会以一种糟糕的方式影响GC,但是当一个对象没有正确地返回到池中时,太小的东西没有提供任何细微的错误等等。多线程应用程序的性能更差,因为没有实例化新对象并重新使用缓存的那些,有人必须块等
在阅读本文之前,我一直认为推荐的方法是使用对象池
在读完这本书之后,事实证明它实际上是一种反模式(如果没有用于 确实经过验证的昂贵的 对象)。
因此,只需根据需要使用普通的new
分配对象,如果您的对象分配确实证明是昂贵的(通过分析等),那么请开始研究池化和缓存策略。
@Jeffrey恕我直言的建议显示了一个很好的方法来开始调查你的对象是否真的很贵。这是一个起点。
答案 3 :(得分:1)
我做了很多处理数百万个对象的项目,实例化对象从来就不是主要的性能问题。
只要你创建IO,比如从数据库读取或读取文件,创建新的objets就会非常快。
答案 4 :(得分:1)
XY结构实际上只是对您的数据成员进行了巧妙的重命名。除了将数据放在错误的类中(并为开销创建第二个类)之外,它不会给你带来任何额外的东西。
相比之下,工厂方法可以节省分配重复点(如0,0)的需要(如果已经分配了它们)。如果您获得0,0的后续请求,则可以缓存这些点并从缓存中返回相同的点。
根据您的工厂结构,您甚至可以回收您的点并“回收它们”,这意味着“重置它们的x和y坐标,在第二次使用中返回相同的对象”。但是,这样的技术通常不赞成,好像你没有办法在重置X和Y值之前验证一个点是无法到达的,你通常会在程序中引入不需要的行为。
在任何情况下,我都不建议在工厂发布之后将这些要点“更新”;因为,如果它们是,那么在工厂类中包装点身份管理的整个能力变得如此复杂,这可能是不值得的。
答案 5 :(得分:0)
你好像正在重新发明Object Pool,如果你真的需要它,这是完全合理的。
但是你应该阅读这个模式,如果你使用它就适当地命名。 “工厂”已用于太多事情。