首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用JVM /编译器优化对象的未使用属性

用JVM /编译器优化对象的未使用属性
EN

Stack Overflow用户
提问于 2016-04-19 15:55:48
回答 3查看 853关注 0票数 4

我的类包含一些从未在任何地方使用过的属性(这是我真实场景的演示)。我听说JVM优化了Java代码。

JVM /编译器是否优化/删除对象的未使用属性?

代码语言:javascript
复制
public class A {
   private int unused1 = 100;// never called anywhere inside object
   public int unused2 = 999;// never called anywhere in the application 
}

我知道我需要努力学习JVM、编译器和优化。但答案是需要的,因为在短时间内,我必须决定是手动从一个大型代码库(大约10,000个java文件)中删除所有(尽可能多的)未使用的变量,还是只依赖于JVM优化。

期待一些有趣而富有成果的建议。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-04-19 16:35:22

不幸的是,它们并没有那么神奇--希望如此,您别无选择,只能使用像PMDFindBugs这样的工具来清理代码,这些工具将帮助您发现此类问题等等。

票数 2
EN

Stack Overflow用户

发布于 2016-04-19 16:13:04

TL;DR:不,JVM编译器(javac)不会优化未使用的变量。

让我们看看javac编译器产生的字节码。

将此用作测试类:

代码语言:javascript
复制
public class Test {

    private int test = 5;
    private int test2 = 10;
    private String aString = "HelloWorld";
}

生产:

代码语言:javascript
复制
Classfile /C:/Users/Huw/Desktop/Test.class


Last modified 19-Apr-2016; size 331 bytes
  MD5 checksum 1c49b13d1d5d8a2c52924b20753122af
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#19         // java/lang/Object."<init>":()V
   #2 = Fieldref           #6.#20         // Test.test:I
   #3 = Fieldref           #6.#21         // Test.test2:I
   #4 = String             #22            // HelloWorld
   #5 = Fieldref           #6.#23         // Test.aString:Ljava/lang/String;
   #6 = Class              #24            // Test
   #7 = Class              #25            // java/lang/Object
   #8 = Utf8               test
   #9 = Utf8               I
  #10 = Utf8               test2
  #11 = Utf8               aString
  #12 = Utf8               Ljava/lang/String;
  #13 = Utf8               <init>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               SourceFile
  #18 = Utf8               Test.java
  #19 = NameAndType        #13:#14        // "<init>":()V
  #20 = NameAndType        #8:#9          // test:I
  #21 = NameAndType        #10:#9         // test2:I
  #22 = Utf8               HelloWorld
  #23 = NameAndType        #11:#12        // aString:Ljava/lang/String;
  #24 = Utf8               Test
  #25 = Utf8               java/lang/Object
{
  public Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_5
         6: putfield      #2                  // Field test:I
         9: aload_0
        10: bipush        10
        12: putfield      #3                  // Field test2:I
        15: aload_0
        16: ldc           #4                  // String HelloWorld
        18: putfield      #5                  // Field aString:Ljava/lang/String;
        21: return
      LineNumberTable:
        line 1: 0
        line 3: 4
        line 4: 9
        line 5: 15
}
SourceFile: "Test.java"

如您所见,编译器仍然分配字段属性。

因此,未使用的变量仍将被分配给指针(对象)和内存(用于原语)。

票数 5
EN

Stack Overflow用户

发布于 2016-04-19 17:37:17

我使用来自http://openjdk.java.net/projects/code-tools/jol/的全新(http://openjdk.java.net/projects/code-tools/jol/)进行了一些测试。

测试表明,至少在我的2台机器上,JVM、月亮阶段等等,JIT无法判断某些字段是未使用的,也没有优化它们。

但是,即使JIT 可以,它实际上也没有必要进行特定的优化。

下面是一个测试:

代码语言:javascript
复制
public static long devNull;

public static void main(String[] args) {
    out.println(VM.current().details());

    Wasty wasty = new Wasty();
    Clean clean = new Clean();

    PrintWriter pw = new PrintWriter(out);
    for (int i = 0; i < 10_000_000; i++) {
        devNull += wasty.doSomething();
        devNull += clean.doSomething();
        if (i == 0 || i == 9_999_999) {
            pw.println(GraphLayout.parseInstance(wasty).toFootprint());
            pw.println(GraphLayout.parseInstance(clean).toFootprint());
        }
    }
    pw.close();
}
public class Wasty {
    private long _long;
    private double _double;
    private String _string;
    private long used;
    private int _int;
    private boolean _boolean;

    public long doSomething() {
        return used++;
    }
}
public class Clean {
    private long used;

    public long doSomething() {
        return used++;
    }
}

其结果是:

代码语言:javascript
复制
    # WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
    # Running 64-bit HotSpot VM.
    # Using compressed oop with 3-bit shift.
    # Using compressed klass with 3-bit shift.
    # WARNING | Compressed references base/shifts are guessed by the experiment!
    # WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
    # WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
    # Objects are 8 bytes aligned.
    # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
    # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

    layout.Wasty@5f205aad footprint:
    COUNT       AVG       SUM   DESCRIPTION
    1        48        48   layout.Wasty
    1                  48   (total)


    layout.Clean@2f410acfd footprint:
    COUNT       AVG       SUM   DESCRIPTION
    1        24        24   layout.Clean
    1                  24   (total)


    layout.Wasty@5f205aad footprint:
    COUNT       AVG       SUM   DESCRIPTION
    1        48        48   layout.Wasty
    1                  48   (total)


    layout.Clean@2f410acfd footprint:
    COUNT       AVG       SUM   DESCRIPTION
    1        24        24   layout.Clean
    1                  24   (total)

因此,就占用空间(内存性能)而言,有未使用的字段是很重要的,因为它们实际上消耗内存,并且可能破坏对象的布局。对于未使用字段的第二点是Joop已经提到的代码气味。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36723547

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档