Java 方法中字符串变量的jvm优化

Java 方法中字符串变量的jvm优化,java,garbage-collection,jvm,Java,Garbage Collection,Jvm,在我正在维护的一个项目中,我发现了一个java类,其方法“fn”类似于下面所示的方法 class Test{ public void fn(){ String METHOD_NAME = "fn"; ... sysout("In " + METHOD_NAME); } } 程序无限期地运行,方法“fn”以非常高的频率连续调用。问题是 每次调用fn()时都会创建变量方法_NAME吗 JVM是否会进行一些优化,以便在下次调用fn()时不会对变量方法_NAME进行垃圾收集和

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

class Test{

public void fn(){
    String METHOD_NAME = "fn";
    ...
    sysout("In " + METHOD_NAME);
}
}
程序无限期地运行,方法“fn”以非常高的频率连续调用。问题是

  • 每次调用fn()时都会创建变量方法_NAME吗
  • JVM是否会进行一些优化,以便在下次调用fn()时不会对变量方法_NAME进行垃圾收集和重用
  • 如果我将变量设置为公共静态最终变量,会不会有性能改进?
    (事实上,这样的功能太多了,我想知道是否值得全部更改)
  • (我想字符串池在这里扮演了一些角色)

    谢谢,
    基兰·莫汉(Kiran Mohan)

    你去参加公开静态决赛,这将提高表现。

    “fn”将被拘留。因此,同一对象将被反复使用

    在最坏的情况下,您可以将其替换为:

    String METHOD_NAME = "fn".intern();
    
    虽然我觉得没必要


    将其公开为static final很好。

    字符串文本被放置在常量池中。将字符串放在静态final中没有任何意义-这种行为由JLS保证


    (是的,字符串也将被保留,尽管这与您的关注点无关)

    变量不是垃圾收集的,而是对象

    “fn”是一个字符串文本,因此它将被插入。它不会被垃圾收集(至少在类加载器处于活动状态时是如此;不确定每个CL是否有一个实习生池,或者整个JVM是否有一个实习生池,但这可能无关紧要),并且在每次调用中都会使用相同的string对象

    如果将其设置为公共静态final,肯定会有改进,因为串联可以由编译器完成,而不是在执行时完成

    如果在方法中使其成为最终值(即仍然作为局部变量),则可能具有相同的效果-我不确定

    每次调用fn()时都会创建变量方法_NAME吗

    变量应该是“created”(更好的是“set”),但字符串不是(因为它是驻留在JVM字符串池中的内部化字符串)。所以它只是对同一字符串的新引用

    JVM是否会进行一些优化,以便在下次调用fn()时不会对变量方法_NAME进行垃圾收集和重用

    变量方法名称只是引用的名称。引用的字符串可能位于字符串池中

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

    可能有,但我宁愿忽略这一点,因为这将是微观优化


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

    是的,每次输入方法时都会创建变量
    方法名称
    ,但这是一个非常复杂的问题,非常便宜的操作(事实上,创建2个变量和创建1个变量一样昂贵)

    (即
    字符串
    对象)
    “fn”
    重新创建,但将来自常量字符串池

    但是,“+METHOD\u NAME中的表达式
    ”将被重新计算,并导致每次创建一个新的
    字符串
    对象,因为它不是一个对象


    如果
    METHOD\u NAME
    其中
    static final
    ,那么该表达式也将是一个编译时常量,因此将来自常量池。

    据我所知,METHOD\u NAME——对字符串“fn”的引用将在每次调用fn()时分配。但是,字符串“fn”的对象应该分配一次,因为它是一个字符串常量,将被放入字符串池中


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

    不要建议对字符串文本使用
    intern()
    !这总是不必要的。根据定义。
    intern
    可能相对昂贵(需要在池中搜索字符串),不建议在循环内(尽管不必要)仅完成:
    “+METHOD\u NAME
    中的”也会导致创建新的StringBuilder@卡洛斯:这是正确的(如果
    METHOD\u NAME
    不是一个常数(即不是
    static final
    )。顺便说一句:IO通常比对象创建要昂贵得多。除非您可以避免IO,或者创建了许多可以优化的对象,否则可能不会有太大的区别。检查字节码:在循环中使其成为最终值将具有相同的效果-编译时不进行串联-但仍然有一个变量赋值(可能通过JIT消除)。您的答案质量非常低,而且很可能也是不正确的。