在运行时移除 Java 常量池

Posted

技术标签:

【中文标题】在运行时移除 Java 常量池【英文标题】:Java constant pool removal at runtime 【发布时间】:2016-08-22 01:16:16 【问题描述】:

我有以下 Java 类:

public class Test 

    public static void main(String[] args) 
        if (false) 
            log("String_to_be_never_printed_1");
        

        if (isPrintable()) 
            log("String_to_be_never_printed_2");
        

    

    private static boolean isPrintable() 
        return false;
    

    private static void log(String s) 
        System.out.println(s);
    


在这两个 if 语句中,结果都是错误的。当我为这个类输出常量池表时,我得到:

Constant pool:
   #1 = Class              #2             // Test
   #2 = Utf8               Test
   ....
  #18 = Utf8               isPrintable
  #19 = Utf8               ()Z
  #20 = String             #21            // String_to_be_never_printed_2
  #21 = Utf8               String_to_be_never_printed_2
  #22 = Methodref          #1.#23         // Test.log:(Ljava/lang/String;)V
  #23 = NameAndType        #24:#25        // log:(Ljava/lang/String;)V
  ...

String_to_be_never_printed_2 存在 (#20),而 String_to_be_never_printed_1 无处可见。这是预期的,因为编译器优化了第一个 if 语句。

我的问题是虚拟机是否会设法从常量池中删除 String_to_be_never_printed_2(因为它永远不会被使用)?

【问题讨论】:

回答这个问题可能会帮助你为什么它不会被删除***.com/questions/23121345/… 【参考方案1】:

堆内存中的对象可以被 JVM 本身进行垃圾回收。常量池中的对象不会全部被垃圾回收,因为它们对分配给 JVM 的内存大小没有太大影响。

【讨论】:

【参考方案2】:

不会从常量池中删除任何内容。无论如何,这样做没有任何意义,因为删除对实际内存大小没有影响

【讨论】:

javac 执行编译时已知的内联常量。如果编译知道代码不能运行,可以去掉+1 你的意思是没有目的,因为字符串池的实际大小与堆大小相比微不足道? @benjamin.d 不,我的意思是常量池在内存中设置为固定大小,并且在执行开始之前位于堆外。垃圾收集只在堆中运行,它在常量池上运行是没有意义的,因为没有其他东西可以进入这个内存

以上是关于在运行时移除 Java 常量池的主要内容,如果未能解决你的问题,请参考以下文章

Java运行时常量池是啥?

java运行时数据区域

Java运行时数据区域(堆 栈 方法区 常量池)

JVM 常量池运行时常量池字符串常量池

android EditText,单击另一个对象时移除焦点

java 常量池