Tôi đang thực hiện một số thử nghiệm với escape analysis trong Java 7 để hiểu rõ hơn đối tượng nào đủ điều kiện để phân bổ stack.Đủ điều kiện để phân tích thoát/phân bổ ngăn xếp với Java 7
Đây là mã tôi đã viết để kiểm tra phân bổ stack:
import java.util.ArrayList;
import java.util.Iterator;
public class EscapeAnalysis {
private static final long TIME_TO_TEST = 10L * 1000L; // 10s
static class Timestamp {
private long millis;
public Timestamp(long millis) {
this.millis = millis;
}
public long getTime() {
return millis;
}
public void setTime(long time) {
millis = time;
}
}
public static void main(String[] args) {
long r = 0;
System.out.println("test1");
r += test1();
System.out.println("test2");
r += test2();
System.out.println("test3");
r += test3();
System.out.println("test4");
r += test4();
System.out.println("test5");
r += test5();
System.out.println("test6");
r += test6();
System.out.println(r);
}
public static long test1() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
r += new Timestamp(System.currentTimeMillis()).getTime();
}
return r;
}
public static long test2() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
for (Iterator<Integer> it = l.iterator(); it.hasNext();) {
r += it.next().longValue();
}
}
return r;
}
public static long test3() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Timestamp ts = new Timestamp(System.currentTimeMillis());
ts.setTime(42);
r += ts.getTime();
}
return r;
}
public static long test4() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Iterator<Integer> it = l.iterator();
r += it.next().longValue();
r += it.next().longValue();
r += it.next().longValue();
r += it.next().longValue();
}
return r;
}
public static long test5() {
ArrayList<Integer> l = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; ++i) {
l.add(i);
}
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
Iterator<Integer> it = l.iterator();
for (int i = 0; i < l.size(); ++i) {
r += it.next().longValue();
}
}
return r;
}
public static long test6() {
long r = 0;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIME_TO_TEST) {
for (Timestamp ts = new Timestamp(System.currentTimeMillis());
ts.getTime() > 0;
ts.setTime(ts.getTime() + System.currentTimeMillis())) {
r += ts.getTime();
}
}
return r;
}
}
Và đây là những gì nó ra với Java 7 trên Linux
java -server -version
java version "1.7.0_02"
Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
Java HotSpot(TM) 64-Bit Server VM (build 22.0-b10, mixed mode)
java -server -verbose:gc -XX:CompileThreshold=1 -cp bin EscapeAnalysis
test1
test2
[GC 15616K->352K(59776K), 0,0014270 secs]
[GC 15968K->288K(59776K), 0,0011790 secs]
[GC 15904K->288K(59776K), 0,0018170 secs]
[GC 15904K->288K(59776K), 0,0011100 secs]
[GC 15904K->288K(57152K), 0,0019790 secs]
[GC 15520K->320K(56896K), 0,0011670 secs]
[GC 15232K->284K(56256K), 0,0011440 secs]
test3
test4
test5
[GC 14876K->348K(55936K), 0,0005340 secs]
[GC 14620K->348K(56000K), 0,0004560 secs]
[GC 14300K->316K(55296K), 0,0004680 secs]
[GC 13948K->316K(55488K), 0,0003590 secs]
[GC 13692K->316K(54784K), 0,0004580 secs]
[GC 13436K->316K(54976K), 0,0005430 secs]
[GC 13180K->316K(54272K), 0,0004500 secs]
[GC 12924K->316K(54464K), 0,0005090 secs]
[GC 12668K->316K(53760K), 0,0004490 secs]
[GC 12412K->316K(53888K), 0,0004350 secs]
[GC 12156K->316K(53312K), 0,0005060 secs]
test6
6737499643744733086
Tôi đang sử dụng các bản ghi GC để biết liệu đối tượng là được phân bổ trên ngăn xếp (ý tưởng từ Escape analysis in Java) có thể không đáng tin cậy 100% nhưng có vẻ là gợi ý tốt.
Baed trên đầu ra, phân bổ ngăn xếp hoạt động cho test1, test3, test4 và test6 và không hoạt động cho test2 và test5. Tôi không hiểu tại sao điều này không làm việc với một iterator trong cho vòng mặc dù nó hoạt động
- với một iterator bên ngoài một cho vòng lặp (xem test4),
- với một đối tượng bên trong một cho- vòng lặp (xem test6).
Tôi đã đọc mã cho số ArrayList iterator và tôi không hiểu tại sao nó không đủ điều kiện phân bổ ngăn xếp trong thử nghiệm 2 và 5 vì nó không thoát khỏi phương pháp hiện tại cũng như chuỗi hiện tại.
Bất kỳ ý tưởng nào?
bạn có thể thử sử dụng lệnh gọi threadmxbean hotspot cụ thể để nhận các byte được chỉ định theo chuỗi sau mỗi lần kiểm tra - http://docs.oracle.com/javase/6/docs/jre/api/management/extension/com/ mặt trời/quản lý/ThreadMXBean.html # getThreadAllocatedBytes (long) - như một biện pháp đáng tin cậy hơn – Matt
cung cấp byte sau được phân bổ cho mỗi thử nghiệm (test1 - 28344, test2 - 29813408, test3 - 114968, test4 - 411480, test5 - 69673176, test6 - 1368) với EA trên và (test1 - 3764906168, test2 - 88636496, test3 - 3867438248, test4 - 6105335224, test5 - 68352808, test6 - 1400) với EA tắt – Matt
bạn cũng có thể sử dụng bản dựng gỡ lỗi và '-XX: + UnlockDiagnosticVMOptions - XX: + PrintEscapeAnalysis -XX: + PrintEliminateAllocations' – Matt