在下面的代码中,我们在一个循环中以一个角度旋转一个复数,然后确认结果数字与我们开始的数字相同。
public class Complex {
private float r, i;
...
public Complex(Complex other) {
r = other.r;
i = other.i;
}
}
Complex z1 = new Complex(..);
Complex z1_save = new Complex(z1);
Complex z2 = new Complex();
Complex k = new Complex();
k.set_to_first_root_of_unity(8);
int n = 64;
while(n-- != 0) {
z1.multiply(k, z2);
z1 = new Complex(z2); // Line Y
}
Assert.assertEquals(true, z1.equals(z1_save));
在Java中是否有办法使用构造函数public Complex(Complex other)
而不是clone()
编写第Y行,并确保64个对象不会被垃圾回收?
更新:如果不参考交互式应用程序的上下文,似乎无法以简化的方式提出此问题。到目前为止,当前问题的最佳答案(assylias's)是人们不应该担心90%的时间都会创建对象和垃圾收集。在重绘期间,有必要在100%的时间内担心它。我现在重申了here的问题。
答案 0 :(得分:2)
我担心GC不必要地运行64次效率低下。
这是一种不必要的担忧。如果您的对象属于年轻一代(他们将考虑其范围),GC将是免费的(如0成本)。
当GC在年轻代上运行时,它只会通过活动对象(不会访问符合GC条件的对象),因此GC时间只是活动对象的函数。
老一代的故事不同,但你的本地物品不会达到那个阶段。
参考 - Brian Goetz,强调我的:
如何解除分配?
但是分配只是内存管理的一半 - 解除分配是另一半。事实证明,对于大多数对象,直接垃圾收集成本为零。这是因为复制收集器不需要访问或复制死对象,只有活对象。因此,在分配后不久就成为垃圾的对象不会给收集周期带来任何工作量。
?事实证明,典型的面向对象程序中的绝大多数对象(根据各种研究,在92%到98%之间)“年轻”,这意味着它们在分配后不久就会变成垃圾,通常在下一次之前垃圾收集。 (这个属性被称为世代假设,经过实证检验,发现许多面向对象语言也是如此。)因此,不仅分配速度快,而且对于大多数对象,释放是免费的。
答案 1 :(得分:1)
对于具有十(或大)字段的对象执行构造函数64次,即使对于像手机这样的设备也不是什么大事。
目前尚不清楚你的任务是什么。
如果你真的担心多次调用构造函数并创建太多相同的对象,你可以尝试使用Flightweight模式。
答案 2 :(得分:1)
你的问题(和评论)有点混乱......但这可能只是你的书面英语技能问题。所以我只是假设我明白你的意思。我也假设你的例子"工作" ......它目前没有。
简短的回答是,您可以通过使Complex
对象变为可变来减少对象流失(即创建和释放"临时"对象)。通常,您可以通过添加允许您更改对象状态的setter操作来执行此操作。但这会使您的Complex
课程更难以正确使用。例如:
public static final ZERO = new Complex(0, 0);
// somewhere else
Complex counter = ZERO;
while (counter.lessThan(10)) {
// ....
counter.setRealPart(counter.getRealPart() + 1); // Ooops!!
}
......还有更多类似的错误。
然后问题是这是否会实际减少垃圾收集开销,以及减少多少。
正如@assylias指出的那样,在下一个GC周期中创建然后回收的临时对象的成本非常低。昂贵的物品是DON&T成为垃圾的物品。对于在正常环境中运行的正常程序,很有可能实际上更高效来创建临时对象。
然后存在一个问题,即最新的HotSpot JVM可以做一些已知的事情"转义分析",(如果它有效)可以确定给定的临时对象永远不会在其创建范围之外可见,因此根本不需要在堆中分配。当可以应用该优化时,"对象流失"关注是有争议的。
但是,运行GC可能会导致实时"实时"性能;例如在游戏编程中,用户会注意到游戏是否冻结了几分之一秒。在这种情况下,值得考虑"调整"你的代码减少对象流失。但是还有其他可能的方法......比如使用低暂停垃圾收集器......如果你的平台可以使用它。
@ assylias的评论使另一个重要。小心过早优化。您对Complex
对象的使用直觉......以及由此产生的对象流失......可能非常错误。在所有条件相同的情况下,最好延迟优化工作,直到您分析了应用程序并确定:
Complex
类是一个重要的性能瓶颈。答案 3 :(得分:1)
根本没有理由关注垃圾收集,除非:
用户(也许是您)感知应用程序的性能问题; 和
分析应用程序表明垃圾收集是感知性能问题的根源。
缺少这些条件的:忽略垃圾收集。
通常,Java中的性能调优也是如此。除非你已经证明它有真正的原因,否则不要这样做。
答案 4 :(得分:-1)
如果你想要高效率的w.r.t GC,尽量减少你对新的使用。
因此,在您的示例中,您可以在“行Y”中重复使用该变量,只需使用新值设置字段即可。类似的东西:
while(n-- != 0) {
z1.multiply(k, z2);
z1.setValue(z2); // Line Y
}
其中z1.setValue(X)以与构造函数new Complex(x)相同的方式设置对象的状态。