方法中字符串变量的JVM优化



在我维护的一个项目中,我发现了一个方法"fn"的java类,类似于下面所示的方法

class Test{
public void fn(){
    String METHOD_NAME = "fn";
    ...
    sysout("In " + METHOD_NAME);
}
}

程序无限期地运行,并且以非常高的频率连续调用方法'fn'。问题是

  1. 每次调用fn()时都会创建变量METHOD_NAME吗?
  2. JVM是否会进行一些优化,以便变量METHOD_NAME不会在下次调用fn()时被垃圾收集和重用?
  3. 如果我使变量成为公共静态final,会有性能改进吗?
    (实际上有很多这样的功能,我想知道是否值得改变它们)

(我猜字符串池在这里起了一些作用)

谢谢,Kiran Mohan

是的,每次进入方法时都会创建变量 METHOD_NAME,但这是一个非常非常便宜的操作(实际上创建2个变量和创建1个变量一样昂贵)。

(即String对象)"fn"将不会重新创建,而是来自常量字符串池

然而,表达式"In " + METHOD_NAME将被重新计算并导致每次都创建一个新的String对象,因为它不是编译时常量表达式。

如果METHOD_NAME where static final,那么该表达式也将是编译时常量,因此将来自常量池。

变量不会被垃圾收集-对象会。

"fn"是一个字符串字面值,因此它将被嵌入。它不会被垃圾收集(至少在ClassLoader还活着的时候);不确定每个CL有一个内部池还是整个JVM有一个,但这可能无关紧要),并且每次调用都将使用相同的字符串对象。

如果将其设置为公共静态final,那么肯定是一种改进,因为连接可以由编译器而不是在执行时完成。

如果你让它在方法中的final (即仍然作为一个局部变量),该可能具有相同的效果-我不确定。

"fn"将被拘禁。因此,同一个对象会被反复使用。

在最坏的情况下,你可以用:

String METHOD_NAME = "fn".intern();

虽然我觉得没必要。

据我所知,METHOD_NAME——对String 'fn'的引用将在每次调用fn()时分配。然而,String 'fn'的对象应该分配一次,因为它是一个String常量,将被放在String池中。

将其替换为公共静态final可能是个好主意,但这是出于编程风格而不是性能考虑。

字符串字面值放在常量池中。把字符串放在静态final中没有任何意义——这种行为是由JLS保证的。

(是的,字符串也将被拘禁,尽管这与您的关注点不是特别相关)

每次调用fn()时都会创建变量METHOD_NAME吗?

变量将被"创建"(最好是"设置"),但字符串不会(因为它是驻留在JVM字符串池中的内部化字符串)。所以它只是对同一个字符串的新引用。

JVM是否会做一些优化,以便变量METHOD_NAME不会被垃圾收集,并在下次调用fn()时重用

变量METHOD_NAME只是一个引用的名字。被引用的字符串可能位于字符串池中。

如果我将变量设置为公共静态final,是否会有性能改进?

可能有,但我宁愿忽略它,因为它是微优化。

实际上,为了获得一点性能改进,您应该考虑是否有必要每次都打印日志语句,特别是在生产环境中,因为它可能过于冗长。

你选择public static final,这会提高性能。

最新更新