SORU
18 Kasım 2008, Salı


Ne kadar yavaş Java istisnalar vardır?

Soru: Java istisna işleme aslında yavaş?

Geleneksel bilgelik, Google sonuçları çok istisnai mantık Java normal program akışı için kullanılması gerektiğini söylüyor. İki nedeni genellikle verilen, 1) çok yavaş, hatta bir sipariş büyüklüğü daha yavaş daha düzenli kod (gerekçeler değişir), ve 2) kendi dağınık çünkü insanların beklentisi sadece hataları için işlenmiş olağanüstü bir kod. Bu soru #1.

Örnek olarak, this page açıklar Java istisna işleme gibi "çok yavaş" ve ilgili yavaşlık için yaratılış özel durum iletisi dize - "bu dize daha sonra kullanılan oluşturma istisna nesnesi atılır. Bu hızlı değildir." Makale Effective Exception Handling in Java diyor ki "bunun nedeni, böylece fırlatma istisnalar doğal olarak yavaş yapar istisna işleme ve nesne oluşturma özelliği nedeniyle". Orada başka bir nedeni izleme nesil yığın ne yavaşlatır.

Benim test (Java 1.6.0_07, Java Noktasal 32 bit Linux 10.0 kullanarak), özel durum işleme düzenli kod daha yavaş olduğunu gösterir. Bir yöntem çalışan bazı kod yürüten bir döngü içinde çalıştım. Yöntemin sonunda, olup olmadığını belirten bir Boole kullanıyorumdönüşyaat. Bu şekilde gerçek işlem aynı. Farklı emir yöntemleri çalışan ve benim test süreleri ortalama, JVM ısınma var olabilir düşünmeye çalıştım. Tüm testlerde, en az at kadar hızlı geri dönüşü olmasa daha hızlı oldu (3.1% daha hızlı). Ben tamamen açmak için olasılığı o benim testler hatalıydı, ama hiçbirşey görmedim orada yoluna kod örneği, test karşılaştırmaları, ya da sonuçları son bir yıl içinde iki gösteriyor istisna işleme, Java için aslında yavaş.

Bu yolda bana yol normal kontrol mantığının bir parçası olarak istisnalar attı kullanmam gereken bir API. Kullanımları onları düzeltmek istedim ama artık mümkün olmayabilir. Bunun yerine ileri düşünme bunları övgü gerekiyor?

Kağıt Efficient Java exception handling in just-in-time compilation, yazarlar öneririz varlığının özel durum işleyicileri yalnız, bile istisna atılmaz yeterince önlemek için TAM zamanında derleyici en iyi duruma getirme kodu düzgün, böylece yavaşlatıyor. Henüz bu teoriyi test etmedim.

CEVAP
18 Kasım 2008, Salı


İstisnalar uygulanır ne kadar olduğuna bağlı. En basit yolu setjmp ve longjmp kullanıyor. Bu İŞLEMCİ tüm kayıtları yığını zaten biraz zaman alır) ve muhtemelen diğer bazı veriler gerekiyor oluşturulacak yazılı olduğu anlamına gelir... tüm bu zaten deneyin deyimi olur. Deyim yığın gevşeyin ve tüm kayıtları değerleri (ve VM olası diğer değerler) geri atmak gerekiyor. Bu yüzden denemek ve atmak olduğunu eşit derecede yavaş, çok yavaş, ancak eğer bir istisna atılır, çıkma try bloğu alır hiçbir zaman çoğu durumda (her şeyi koymak yığını olan temizler otomatik bir yöntemi var).

Güneş ve diğerleri bu ve tabii ki muhtemelen vasatın altında daha hızlı ve daha hızlı zaman içerisinde olduğunu görüyor. Başka bir yolu var uygulamak için istisnalar sağlar deneyin kendisi ışık hızında (aslında hiçbir şey için hiç denemek genel - her şeye ihtiyacı var ki zaten bittiğinde sınıfı tarafından yüklendikten VM) ve bunu yapan atmak değil oldukça yavaş. Bu yeni, daha iyi tekniği bilmiyorum...

...ama Java yazıyorsun kodunuzu daha sonra tek bir JVM üzerinde çalışır, böylece belirli bir sistem? Eğer şimdiye kadar başka bir platform ya da söyleyen başka bir JVM sürümü (başka bir satıcı muhtemelen) üzerinde çalışabilir eğer bu yana da hızlı bir şekilde uygulamasını kullanın? Hızlı bir yavaş daha karmaşık ve tüm sistemlerde kolayca mümkündür. Taşınabilir kalmak mı istiyorsun? O zaman istisnalar hızlı olmak güvenmeyin.

Bu da deneyin bir blok içinde ne büyük bir fark yaratıyor. Deneyin bir blok açın ve asla bu deneyin blok içinde herhangi bir yöntem çağrısı, deneyin blok JİT sonra aslında basit bir goto gibi atmak bir tedavi olarak ultra hızlı olacak. O değil ve eğer bir özel durum yığın (yalnızca catch işleyicileri atlamak gerekiyor) rahatlamaya ihtiyacı var yığın durumunu kaydetmek gerekiyor. Ancak, bu genellikle ne değildir. Genellikle deneyin bir blok açın ve sonra da bir istisna değil atmak olabilecek bir yöntem diyorsun? Ve eğer sen kendi yöntemi içinde deneyin bloğu kullanırsanız bile, ne tür bir yöntem bu, bunun başka bir yöntemi çağırmaz mı olacak? Sadece bir sayı hesaplar. Ne için istisnalar ihtiyacınız var? Program akışı düzenlemek için çok daha zarif yolları vardır. Başka çok fazla bir şey ama basit matematik için, harici bir yöntem aramak zorunda kalacak ve bu da zaten yerel bir try avantajı yok.

Aşağıdaki test kodu bakın:

public class Test {
    int value;


    public int getValue() {
        return value;
    }

    public void reset() {
        value = 0;
    }

    // Calculates without exception
    public void method1(int i) {
        value = ((value   i) / i) << 1;
        // Will never be true
        if ((i & 0xFFFFFFF) == 1000000000) {
            System.out.println("You'll never see this!");
        }
    }

    // Could in theory throw one, but never will
    public void method2(int i) throws Exception {
        value = ((value   i) / i) << 1;
        // Will never be true
        if ((i & 0xFFFFFFF) == 1000000000) {
            throw new Exception();
        }
    }

    // This one will regularly throw one
    public void method3(int i) throws Exception {
        value = ((value   i) / i) << 1;
        // i & 1 is equally fast to calculate as i & 0xFFFFFFF; it is both
        // an AND operation between two integers. The size of the number plays
        // no role. AND on 32 BIT always ANDs all 32 bits
        if ((i & 0x1) == 1) {
            throw new Exception();
        }
    }

    public static void main(String[] args) {
        int i;
        long l;
        Test t = new Test();

        l = System.currentTimeMillis();
        t.reset();
        for (i = 1; i < 100000000; i  ) {
            t.method1(i);
        }
        l = System.currentTimeMillis() - l;
        System.out.println(
            "method1 took "   l   " ms, result was "   t.getValue()
        );

        l = System.currentTimeMillis();
        t.reset();
        for (i = 1; i < 100000000; i  ) {
            try {
                t.method2(i);
            } catch (Exception e) {
                System.out.println("You'll never see this!");
            }
        }
        l = System.currentTimeMillis() - l;
        System.out.println(
            "method2 took "   l   " ms, result was "   t.getValue()
        );

        l = System.currentTimeMillis();
        t.reset();
        for (i = 1; i < 100000000; i  ) {
            try {
                t.method3(i);
            } catch (Exception e) {
                // Do nothing here, as we will get here
            }
        }
        l = System.currentTimeMillis() - l;
        System.out.println(
            "method3 took "   l   " ms, result was "   t.getValue()
        );
    }
}

Sonuç:

method1 took 972 ms, result was 2
method2 took 1003 ms, result was 2
method3 took 66716 ms, result was 2

Deneyin bloğu yavaşlama plan süreçleri gibi faktörlerin ekarte etmek için çok küçük. Ama catch bloğu her şeyi öldürüp 66 kez yavaş yaptı!

Dediğim gibi, sonuç olmayacak o kötü olursa Sen Koy/yakalamak ve atmak içinde aynı yöntem (method3), ama bu özel bir JİT optimizasyon olmaz güvenmek. Ve bu iyileştirme kullanırken bile, atmak hala çok yavaş. Burada yapmaya çalıştığınız şey ne bilmiyorum ama kesinlikle kullanma/atmak/yakalamak deneyin daha bunu yapmanın daha iyi bir yolu yoktur.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • EmbarkToHeaven

    EmbarkToHeav

    3 EYLÜL 2007
  • macpulenta

    macpulenta

    9 EYLÜL 2006
  • rtisticsdev

    rtisticsdev

    31 Mayıs 2012