最近我被一位开发人员问过,但无法提供答案......
在Java中,变量如何处理/何时处理?是吗?
假设我们有一个run()方法,每秒调用50-75次(大大简化的例子)......
public void run() {
long lastTime = System.nanoTime();
double unprocessed = 0;
int ticks = 0;
int frames = 0;
double nsPerTick = 1000000000.0 / 60.0;
long now = System.nanoTime();
unprocessed += (now - lastTime) / nsPerTick;
lastTime = now;
ticks++;
tick();
unprocessed -= 1;
}
将这些变量(lastTime,unprocessed,ticks等)放到更高的范围内会使程序运行得更好/更有效 - 到一个不是每秒创建和使用多次的地方吗?
答案 0 :(得分:3)
由于这些变量是在stack
中创建的,因此不会给您带来任何性能提升。
阅读本文以了解有关Java中的Object destructions的更多信息:
答案 1 :(得分:3)
Java使用garbage collector,因此未使用的对象会自动处理。在您的示例中,您只使用局部变量,它们在堆栈上分配,这非常快(这里不涉及垃圾收集)。将这些变量移动到外部函数(“范围更高”)将无济于事。
答案 2 :(得分:1)
在Java中,变量如何处理/何时处理?是吗?
首先,让我们清楚一点。在Java中,存在称为变量的东西,并且存在称为对象的东西。变量和对象不是一回事。
Java中的变量始终是其他内容的一部分:
局部变量是方法调用的状态的一部分。当它超出范围时会被处理掉。 通常是意味着方法调用结束并且方法调用的堆栈帧从调用堆栈中弹出。
实例变量(或字段或属性)是对象的一部分。当对象被处置时它会被处理掉。
静态变量(或类变量)是类的一部分,只有在卸载类时才会处理。
在您的示例中,所有变量都是局部变量,并且在当前对run()
方法的调用返回时(或由于异常而终止)将被“处理掉”。
将这些变量(lastTime,unprocessed,ticks等)放到更高的范围内会使程序运行得更好/更有效 - 到一个不是每秒创建和使用多次的地方吗?
没有用。创建或处理局部变量的增量成本是ZERO 1 。使用局部变量的成本(如果有的话) less 是使用实例变量的成本。唯一的成本可能是初始化它,但无论如何你都要承担这笔费用;例如在每个方法调用上重新初始化一个实例变量。
实际上,将局部变量转换为实例变量可能实际上是一件坏事。这意味着该方法现在使用对象变量来表示其状态,使其不可重入。 (目前还不清楚这是否重要。这取决于run()
方法是否以一种要求它可重入的方式使用......通常情况并非如此。)
1 - 这有点过于简单了。如果您有足够多的局部变量和/或深度递归方法,那么您可能需要使用大于正常的线程堆栈大小。额外的内存使用将是成本。
答案 3 :(得分:0)
这个问题的答案取决于Java的Garbage集合,它有一个较小的片段,称为“nursery gc”,它被频繁调用并且不会导致jvm停止。所有局部变量都转到这个托儿所gc。当此方法执行完成时;所有这些变量都符合GC的条件;并在调用nursery gc时删除。
回答你的问题是否更好地将这些变量移出运行方法。虽然JVM在每次发布时都变得越来越聪明;创建对象对性能的影响较小。但即使是那么微小的影响,我仍然感觉到;我认为使对象全局化是没有害处的。
虽然在这种情况下所有变量都是原始的;它不会产生任何影响。
答案 4 :(得分:0)
Id取决于JVM运行模式和JVM版本。
但大多数JVM版本的执行方式如下:
当JVM在-client
模式下运行时,代码将逐行运行。
但是当JVM在-server
模式下运行时,代码将被优化:
假设tick()方法是:
public void tick(){
System.out.println("tick");
}
优化后的最终代码:
public void run() {
long lastTime = System.nanoTime();
int ticks = 0;
int frames = 1;
double unprocessed = (System.nanoTime() - lastTime) / 16666666.66 -1 ;
// tick method will inline here instead of invoking tick();
System.out.println("tick");
}