编译器能做的不多,因为它不知道add
方法做了什么。这是循环体的生成代码。如您所见,它只是调用add
并存储结果。
25: iload 5
27: iload 4
29: if_icmpge 51
32: aload_3
33: iload 5
35: aaload
36: astore 6
38: aload_1
39: aload 6
41: invokevirtual #5; //Method java/math/BigInteger.add:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
44: astore_1
45: iinc 5, 1
48: goto 25
理论上,Java 虚拟机运行时系统可以更聪明。例如,它可以检测到一个对象不断地覆盖另一个刚刚分配的对象,并为它们交换两个分配缓冲区。但是,正如我们在启用垃圾收集日志记录的情况下运行以下程序所看到的那样,遗憾的是情况并非如此
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Random;
class Test {
public static void main(String[] args) {
ArrayList <BigInteger> nums = new ArrayList<BigInteger>();
final int NBITS = 100;
final int NVALS = 1000000;
System.out.println("Filling ArrayList");
Random r = new Random();
for (int i = 0; i < NVALS; i++)
nums.add(new BigInteger(NBITS, r));
System.out.println("Adding ArrayList values");
BigInteger A = new BigInteger("0");
for(BigInteger n : nums) {
A = A.add(n);
}
System.gc();
}
}
在添加过程中查看垃圾收集调用。
C:\tmp>java -verbose:gc Test
Filling ArrayList
[GC 16256K->10471K(62336K), 0.0257655 secs]
[GC 26727K->21107K(78592K), 0.0304749 secs]
[GC 53619K->42090K(78592K), 0.0567912 secs]
[Full GC 42090K->42090K(122304K), 0.1019642 secs]
[GC 74602K->65857K(141760K), 0.0601406 secs]
[Full GC 65857K->65853K(182144K), 0.1485418 secs]
Adding ArrayList values
[GC 117821K->77213K(195200K), 0.0381312 secs]
[GC 112746K->77245K(228288K), 0.0111372 secs]
[Full GC 77245K->137K(228288K), 0.0327287 secs]
C:\tmp>java -version
java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)