我的类包含一些从未在任何地方使用过的属性(这是我真实场景的演示)。我听说JVM优化了Java代码。
JVM /编译器是否优化/删除对象的未使用属性?
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优化。
期待一些有趣而富有成果的建议。
发布于 2016-04-19 16:35:22
不幸的是,它们并没有那么神奇--希望如此,您别无选择,只能使用像PMD或FindBugs这样的工具来清理代码,这些工具将帮助您发现此类问题等等。
发布于 2016-04-19 16:13:04
TL;DR:不,JVM编译器(javac)不会优化未使用的变量。
让我们看看javac编译器产生的字节码。
将此用作测试类:
public class Test {
private int test = 5;
private int test2 = 10;
private String aString = "HelloWorld";
}生产:
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"如您所见,编译器仍然分配字段属性。
因此,未使用的变量仍将被分配给指针(对象)和内存(用于原语)。
发布于 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 可以,它实际上也没有必要将进行特定的优化。
下面是一个测试:
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++;
}
}其结果是:
# 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已经提到的代码气味。
https://stackoverflow.com/questions/36723547
复制相似问题