[英]Java - LinkedList - Performance decreases with the number of different classes in it
以下代碼測量從接口處理程序 100次調用方法句柄(對象o)所花費的時間(是的,它的質量差異分析):
package test;
import java.util.LinkedList;
public class Test {
static int i = 0;
private interface Handler {
public void handle(Object o);
}
private static class SuperHandler implements Handler {
public void handle(Object o) { i += 1; }
}
private static class NoSuperHandler implements Handler {
public void handle(Object o) { i += 1; }
}
private static class LulSuperHandler implements Handler {
public void handle(Object o) { i += 1; }
}
private static class LilSuperHandler implements Handler {
public void handle(Object o) { i += 1; }
}
private static class LolSuperHandler implements Handler {
public void handle(Object o) { i += 1; }
}
private static class LalSuperHandler implements Handler {
public void handle(Object o) { i += 1; }
}
private static class LylSuperHandler implements Handler {
public void handle(Object o) { i += 1; }
}
private static class LzlSuperHandler implements Handler {
public void handle(Object o) { i += 1; }
}
public static void main(String[] args) {
LinkedList<Handler> ll = new LinkedList<Handler>();
for(int j = 0; j < 100; j++) {
if((j % 8) == 0) ll.add(new SuperHandler());
if((j % 8) == 1) ll.add(new NoSuperHandler());
if((j % 8) == 2) ll.add(new LulSuperHandler());
if((j % 8) == 3) ll.add(new LilSuperHandler());
if((j % 8) == 4) ll.add(new LolSuperHandler());
if((j % 8) == 5) ll.add(new LalSuperHandler());
if((j % 8) == 6) ll.add(new LylSuperHandler());
if((j % 8) == 7) ll.add(new LzlSuperHandler());
}
long begin = System.currentTimeMillis();
for(int j = 0; j < 1000000; j++) for(Handler h: ll) h.handle(null);
System.out.println("time in ms: " + (System.currentTimeMillis() - begin));
System.out.println("i: " + i);
}
}
事實是,如果LinkedList只包含一種Handler ,例如SuperHandler ,則執行時間小於它們是2,3等不同種類的Handler 。 每次我在列表中添加一種新的Handler時,性能會下降。
例如,當我只改變這部分時,我獲得了比上面更好的表現:
for(int j = 0; j < 100; j++) {
if((j % 2) == 0) ll.add(new SuperHandler());
if((j % 2) == 1) ll.add(new NoSuperHandler());
}
這里有特殊的優化操作嗎? JAVA架構中的性能會降低多少? 我的測試是錯誤的,因為未使用的Handler被編譯器“刪除”或“隱藏”了嗎? (我正在使用Linux Ubuntu - 來自Oracle的JAVA 1.7)
這里有特殊的優化操作嗎?
是。 Hotspot非常聰明地處理虛擬方法。 如果只有一些接口的實現,並且這些實現很小,它可以通過檢查正確的類型和內聯代碼來避免完整的vtable-lookup。
當你有幾個不同的實現時,它會回到vtable實現。 (Hotspot非常聰明,可以撤銷不再實用的優化。我很震驚,它們都掛在一起,但顯然確實如此。)
請注意,這不是列表中有多少不同的類 - 這里有更多的內容。 有關詳細信息,請參閱Peter的答案。
我同意Jon的回答,但我相信它是在代碼點調用的類型數量之間產生差異。 在下面的示例中,將加載所有8個類,並且對於列表中相同數量的元素運行相同的代碼,除了一個列表有8個,另一個列表有2個不同類型。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class Test {
static int i = 0;
private interface Handler {
public void handle();
}
public static void main(String[] args) {
List<Handler> ll8 = new ArrayList<Handler>();
for (int j = 0; j < 128; j += 8) {
ll8.add(new SuperHandler());
ll8.add(new NoSuperHandler());
ll8.add(new LulSuperHandler());
ll8.add(new LilSuperHandler());
ll8.add(new LolSuperHandler());
ll8.add(new LalSuperHandler());
ll8.add(new LylSuperHandler());
ll8.add(new LzlSuperHandler());
}
List<Handler> ll2 = new ArrayList<Handler>();
for (int j = 0; j < 128; j += 2) {
ll2.add(new SuperHandler());
ll2.add(new NoSuperHandler());
}
for (int j = 0; j < 5; j++) {
test8(ll8);
test8a(ll8);
test2(ll2);
}
System.out.println("i: " + i);
}
private static void test8(List<Handler> ll8) {
long begin = System.nanoTime();
for (int j = 0; j < 1000000; j++) for (Handler h : ll8) h.handle();
System.out.println("8 classes, time in ms: " + (System.nanoTime() - begin) / 100000 / 10.0);
}
private static void test8a(List<Handler> ll8) {
long begin = System.nanoTime();
for (int j = 0; j < 1000000; j++)
for (int k = 0; k < ll8.size(); k += 8) {
ll8.get(k + 0).handle();
ll8.get(k + 1).handle();
ll8.get(k + 2).handle();
ll8.get(k + 3).handle();
ll8.get(k + 4).handle();
ll8.get(k + 5).handle();
ll8.get(k + 6).handle();
ll8.get(k + 7).handle();
}
System.out.println("8 classes unrolled, time in ms: " + (System.nanoTime() - begin) / 100000 / 10.0);
}
private static void test2(List<Handler> ll2) {
long begin = System.nanoTime();
for (int j = 0; j < 1000000; j++) for (Handler h : ll2) h.handle();
System.out.println("2 classes, time in ms: " + (System.nanoTime() - begin) / 100000 / 10.0);
}
private static class SuperHandler implements Handler {
public void handle() { i += 1; }
}
private static class NoSuperHandler implements Handler {
public void handle() { i += 1; }
}
private static class LulSuperHandler implements Handler {
public void handle() { i += 1; }
}
private static class LilSuperHandler implements Handler {
public void handle() { i += 1; }
}
private static class LolSuperHandler implements Handler {
public void handle() { i += 1; }
}
private static class LalSuperHandler implements Handler {
public void handle() { i += 1; }
}
private static class LylSuperHandler implements Handler {
public void handle() { i += 1; }
}
private static class LzlSuperHandler implements Handler {
public void handle() { i += 1; }
}
}
版畫
8 classes, time in ms: 1467.9
8 classes unrolled, time in ms: 144.7
2 classes, time in ms: 515.8
8 classes, time in ms: 1455.1
8 classes unrolled, time in ms: 126.2
2 classes, time in ms: 509.6
8 classes, time in ms: 1234.1
8 classes unrolled, time in ms: 107.8
2 classes, time in ms: 274.3
8 classes, time in ms: 1212.0
8 classes unrolled, time in ms: 108.1
2 classes, time in ms: 273.0
8 classes, time in ms: 1208.8
8 classes unrolled, time in ms: 107.8
2 classes, time in ms: 274.5
i: 1920000000
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.