我记得有人告诉我一个好的。但我不记得了。我花了最后20分钟与谷歌试图了解更多。
由于垃圾回收而导致性能下降的错误/不良代码的示例是什么?
答案 0 :(得分:2)
- 有时它有助于显式地使引用无效,以使它们符合以前的垃圾收集条件:
public class Stack {
private static final int MAXLEN = 10;
private Object stk[] = new Object[MAXLEN];
private int stkp = -1;
public void push(Object p) {stk[++stkp] = p;}
public Object pop() {return stk[stkp--];}
}
以这种方式重写pop方法有助于确保及时完成垃圾收集:
public Object pop() {
Object p = stk[stkp];
stk[stkp--] = null;
return p;
}
答案 1 :(得分:2)
由于垃圾回收而导致性能下降的错误/不良代码的示例是什么?
使用分代垃圾收集器时,以下效率低下:
对堆中的引用进行变换,因为写入障碍比指针写入要贵得多。考虑将堆分配和引用分别用数组类型和整数索引替换为数组。
创造长寿的临时工。当它们在苗圃世代中存活下来时,必须对它们进行标记,复制并更新所有指针。如果可以合并更新以重复使用旧版本的集合,请执行此操作。
复杂的堆拓扑。再次考虑用索引替换许多引用。
深度线程堆栈。尽量保持堆栈浅,以便GC更容易整理全局根源。
然而,我不会称这些为“坏”,因为他们没有任何客观上的错误。当与这种垃圾收集器一起使用时,它们效率很低。使用手动内存管理,不会出现任何问题(尽管许多问题已被替换为等效问题,例如malloc
与池分配器的性能)。对于其他种类的GC,这些问题中的一些消失了,例如,一些GC没有写入障碍,标记区域GC应该能够更好地处理长寿命临时值,并非所有虚拟机都需要线程堆栈。
答案 2 :(得分:1)
当你有一些涉及创建新对象实例的循环时:如果循环次数非常高,你会产生大量垃圾,导致垃圾收集器更频繁地运行,从而降低性能。
答案 3 :(得分:0)
一个例子是保存在成员变量或静态变量中的对象引用。这是一个例子:
class Something {
static HugeInstance instance = new HugeInstance();
}
问题是垃圾收集器无法知道,何时不再需要此实例。因此,通常最好将事物保存在局部变量中并具有小函数。
答案 4 :(得分:0)
String foo = new String("a" + "b" + "c");
我理解Java现在更好,但在早期会涉及创建和销毁3或4个字符串对象。
答案 5 :(得分:0)
我可以举一个与.Net CLR GC一起使用的例子:
如果从类重写finalize方法而不调用超类Finalize方法,例如
protected override void Finalize(){
Console.WriteLine("Im done");
//base.Finalize(); => you should call him!!!!!
}
当你意外地复活一个物体时
protected override void Finalize(){
Application.ObjJolder = this;
}
class Application{
static public object ObjHolder;
}
当您使用使用Finalize的对象时,需要两个GC集合来删除数据,并且在上述任何代码中您都不会删除它。
答案 6 :(得分:0)
答案 7 :(得分:0)
在大多数现代收藏家中,任何使用终结都会减慢收藏家的速度。而且不仅仅是具有终结器的对象。
答案 8 :(得分:0)
您的自定义服务上没有负载限制器,因此:
答案 9 :(得分:0)
我在Python中进行基于并行单元的仿真时遇到了一个很好的例子。在运行酸洗后,将单元初始化并发送到工作进程。如果您一次有太多单元格,则主节点用完ram。诀窍是让有限数量的单元格打包并将它们发送到集群节点再进行更多操作,记住将已发送的对象设置为“无”。除了计算能力之外,这还允许您使用群集的总RAM执行大型模拟。
这里的应用是基于细胞的火灾模拟,只有主动燃烧的细胞在任何时候都被保存为物体。