Java gerçekten yavaş mı?


180

Java'nın yavaş olduğu için bir üne sahiptir .

  • Java gerçekten yavaş mı?
  • Evet ise, neden? Darboğaz nerede (veya neredeydi)? Verimsiz JVM'ler yüzünden mi? Çöp toplama? JNI ile sarılmış C kodu yerine saf bayt kodu kitaplıkları? Diğer birçok dilde bu özellikler vardır, ancak yavaşlık için bu üne sahip değildirler.

35
insanlar bu kadar gerginleşiyor ... bunun nasıl öznel olabileceğini görmüyorum, ne de tartışmacı. "Kabarcık türünün neden yavaş" gibi bir sorunun aynı sonucu alıp almayacağını merak ediyorum. Teknik bir soru sordum ve teknik cevaplar istedim (ki ben aldım), fakat soruyu öznel ve tartışmacı olarak kapatmak saçma.
Stefano Borini

1
En iyi yorumların çoğunu okudum ve hiçbiri C # GUI tabanlı masaüstü uygulamalarının modern olanlar da dahil olmak üzere herhangi bir Java GUI tabanlı masaüstü uygulamasından çok daha hızlı çalıştığı gerçeğini ele almıyor gibi görünüyor.
BobTurbo

3
.Net webformları, .net MVC, PHP, Rails, Django ve Java dışında Spring'den (iyi duyduğum) her şeyin geniş bir çeşitliliği ile uğraşan bir müşteri tarafı web geliştiricisi olarak, kötü performans / mimari bekliyorum Java ekipleri tarafından inşa edilen arka uçlardan. Ben gerçek sorunun kriterleri değil, daha ziyade orada sadece vasat Java devs bir bok ton olma sorunu şüpheli. Bu dilin hatası değil. Aslında zanaatlarını bileyen ve Java dışındaki dilleri öğrenen Java geliştiricilerinin hatası değildir. Bununla birlikte, Sun, certs, 90'lar ve genel olarak BT endüstrisinin hatası olabilir.
Erik Reppen

Yanıtlar:


236

Modern Java, hala bir bellek domuzu olmasına rağmen, en hızlı dillerden biridir. Java'nın yavaş olduğu için bir ünü vardı , çünkü VM'nin başlaması uzun sürüyordu.

Hala Java yavaş düşünüyorsanız , bkz kriterler oyun sonuçları. Önceden derlenmiş bir dilde (C, Fortran, vb.) Yazılan, sıkıca optimize edilmiş kod onu yenebilir; ancak, Java PHP, Ruby, Python, vb. kadar 10 kat daha hızlı olabilir. Ortak derlenmiş dilleri yenebileceği belirli alanlar vardır (standart kütüphaneler kullanıyorlarsa).

Artık "yavaş" Java uygulamaları için bir mazeret yoktur. Geliştiriciler ve eski kod / kütüphaneler, dilden çok daha fazla suçlanacak. Ayrıca, 'kurumsal' bir şey suçlayın.

"Java yavaş" kalabalığa adaletle, burada hala yavaş olan alanlar var (2013 için güncellendi):

  • Kütüphaneler genellikle performans için değil, "doğruluk" ve okunabilirlik için yazılır. Bence, Java'nın hala kötü bir üne sahip olmasının ana nedeni, özellikle sunucu tarafı. Bu, String sorunlarını katlanarak daha da kötüleştirir. Bazı basit hatalar yaygındır: nesneler genellikle ilkel yerine kullanılır, performansı azaltır ve bellek kullanımını artırır. Birçok Java kitaplığı (standart olanlar dahil), değiştirilebilir veya basit biçimleri (char [] veya StringBuffer) yeniden kullanmak yerine sık sık Dizeler oluşturur. Bu yavaştır ve daha sonra toplamak için tonlarca çöp oluşturur. Bunu düzeltmek için, geliştiricilerin mümkün olduğunca ilkel koleksiyonları ve özellikle Javalution kütüphanelerini kullanmasını öneriyorum.

  • Dize işlemleri biraz yavaş. Java değişmez, UTF-16 kodlu dize nesneleri kullanır. Bu, daha fazla belleğe, daha fazla bellek erişimine ihtiyacınız olduğu ve bazı işlemlerin ASCII'den (C, C ++) daha karmaşık olduğu anlamına gelir. O zaman, taşınabilirlik için doğru karardı, ancak küçük bir performans maliyeti taşıyor. UTF-8 şimdi daha iyi bir seçim gibi görünüyor.

  • Dizi kontrolleri, sınır kontrolleri nedeniyle C'ye göre biraz daha yavaştır . Ceza eskiden büyüktü, ama şimdi küçük (Java 7, gereksiz sınır kontrollerini optimize ediyor).

  • İsteğe bağlı bellek erişiminin olmaması bazı G / Ç ve bit seviyesi işlemeyi yavaşlatabilir (örneğin sıkıştırma / açma). Bu, şu anda çoğu üst düzey dilin güvenlik özelliğidir.

  • Java, C'den çok daha fazla bellek kullanır ve uygulamanız belleğe bağlıysa veya bellek bant genişliğine bağlıysa (önbellekleme, vb.) Bu işlemi yavaşlatır. Flipside, tahsis / dağıtmanın hızlı bir şekilde yanıp sönmesi (yüksek derecede optimize edilmiş). Bu, çoğu üst düzey dilin bir özelliğidir ve açık bellek ayırma yerine nesneler ve GC kullanımı nedeniyle . Ayrıca kötü kütüphane kararları.

  • Her bir akış erişiminde senkronizasyon gerektirmesi nedeniyle (IMO, kötü seçim) akış tabanlı G / Ç yavaş . NIO bunu düzeltti, ancak kullanmak bir acı. Bu, bir seferde bir eleman yerine bir diziye okuma / yazma yaparak bu sorunu çözebilir.

  • Java, C ile aynı düşük düzeyli işlevselliği sağlamaz, bu nedenle bazı işlemleri daha hızlı yapmak için kirli satır içi montajcı püf noktalarını kullanamazsınız. Bu, taşınabilirlik sağlar ve şimdi en üst düzey dillerin bir özelliğidir.

  • Çok eski JVM sürümlerine bağlı Java uygulamalarını görmek yaygındır. Özellikle sunucu tarafı. Bu eski JVM'ler, en son sürümlere kıyasla inanılmaz derecede verimsiz olabilir.

Sonunda Java, bazı performans pahasına güvenlik ve taşınabilirlik sağlamak ve bazı gerçekten zorlu işlemler için göstermek için tasarlandı. Yavaşlık konusundaki itibarının çoğu artık hak edilmiyor.


Bununla birlikte, Java'nın diğer dillerden daha hızlı olduğu birkaç yer vardır :

  • Bellek ayırma ve ayırma işlemi hızlı ve ucuzdur. % 20 HIZLI (veya daha fazla!) Önbelleğe alınmış bir yeniden kullanmak daha yeni, multi-kB dizi tahsis durumlarda gördüm.

  • Nesne örnekleme ve nesne yönelimli özelliklerin kullanımı hızlıdır (bazı durumlarda C ++ 'dan daha hızlıdır), çünkü başlangıçtan itibaren tasarlanmıştır. Bu kısmen açık ayırmadan ziyade iyi GC'den (bir çok küçük nesne ayırımı için daha kolay). Bunu yenen C kodlanabilir (özel bellek yönetimini yuvarlayarak ve verimli bir şekilde malloc yaparak), ancak kolay değildir.

  • Yöntem çağrıları temelde ücretsizdir ve bazı durumlarda büyük yöntem kodundan daha hızlıdır. Etkin Nokta derleyici optimize yöntem çağrılarına yürütme bilgileri kullanır ve çok etkili inlining sahiptir. Ek yürütme bilgilerini kullanarak bazen vaktinden önce derleyicilerden ve hatta (nadir durumlarda) manuel satırdan daha iyi performans gösterebilir. Derleyici satır içi yapmamaya karar verirse yöntem çağrılarının küçük bir performans cezası ile geldiği C / C ++ ile karşılaştırın.

  • Senkronizasyon ve çoklu iş parçacığı kullanımı kolay ve verimlidir. Java başından beri iş parçacığı farkında olacak şekilde tasarlanmıştır ve gösterir. Modern bilgisayarlar genellikle birden çok çekirdeğe sahiptir ve diş çekme dili içine yerleştirildiği için çok kolay faydalanabilirsiniz. Temel olarak standart, tek iş parçacıklı C koduna kıyasla% 100 ila% 300 arasında ekstra hız artışı. Evet, dikkatlice yazılmış C iş parçacığı ve kütüphaneler bunu yenebilir, ancak bu programcı için çok fazla iştir.

  • Dizeler uzunluk içerir: bazı işlemler daha hızlıdır. Bu, null ile ayrılmış dizeleri kullanarak geçer (C'de yaygındır). Java 7'de Oracle, insanlar aptalca kullandıkları ve bellek sızıntıları aldıkları için String.subString () optimizasyonunu gerçekleştirdi.

  • Dizi kopyası oldukça optimize edilmiştir. En son sürümlerde Java, System.arraycopy için elle ayarlanan birleştirici kullanır. Sonuç, dizikopi / memcopy-ağır işlemlerde, kodumun C'deki eşdeğeri makul marjlarla yendiğini gördüm.

  • JIT derleyicisi L1 / L2 önbellek kullanımı konusunda akıllıdır . Önceden derlenmiş programlar, kodlarını gerçek zamanlı olarak üzerinde çalıştıkları belirli CPU ve sistemle değiştiremez. JIT bu şekilde çok verimli bazı döngü dönüşümleri sağlar.

Birkaç diğer tarihi gerçek "Java yavaş" ününe katkıda bulundu:

  • JIT derlemesinden önce (Java 1.2 / 1.3), dil sadece yorumlandı, derlenmedi ve dolayısıyla çok yavaştı.
  • JIT derlemesinin verimli hale gelmesi zaman aldı (her versiyonda büyük iyileştirmeler)
  • Sınıf yüklemesi yıllar içinde çok daha verimli hale geldi. Başlangıçta oldukça verimsiz ve yavaştı.
  • Swing ve UI kodu yerel grafik donanımını çok iyi kullanmadı.
  • Salıncak sadece korkunç. Java'nın masaüstüne neden hiç yakalanmadığı için AWT ve Swing'i suçluyorum.
  • Kütüphane sınıflarında yoğun senkronizasyon kullanımı; senkronize olmayan sürümler artık mevcut
  • Ağ üzerinden tam bir JAR iletmesi ve önyükleme için VM'yi yüklemesi nedeniyle uygulamaların yüklenmesi sonsuza kadar sürer .
  • Yoğun bir performans cezası taşımak için kullanılan senkronizasyon (bu, her Java sürümü için optimize edilmiştir). Ancak, yansıma hala maliyetlidir.

49
Object instantiation and object-oriented features are blazing fast to use (faster than C++ in many cases) because they're designed in from the beginning.ve Collections are fast. Standard Java beats standard C/C++ in this area, even for most optimized C code.burada bağlantılı kanıtlarla desteklenmeyen vahşi iddialardır.
Sjoerd

8
@Sjoerd - İddialar pek vahşi değil - onlar için açık ve C / C ++ ile Java arasındaki varsayılan bellek sisteminin mimarisindeki farklılıkları anlayan herkes için olmalı. Sen olabilir (bunu ücretsiz listeleri, hafıza havuzları ve benzeri şeyler ile) kendi bellek işleyicileri yazarsanız hala çok daha iyisini ya uygular, öyle ki bir kütüphane kullanın.
Rex Kerr

15
@Rex Kerr - Örneğin yığını ayırmak için kullanabiliyorsanız neden bellek işleyicileri kullanıyorsunuz ?! Yığın bellek ayırmayı nesne somutlaştırmasıyla karıştırıyorsunuz.
Sjoerd

20
@Rex Kerr - Temel olarak, Java'daki her şeyin yığın üzerinde bellek ayırmayı içerdiği ve Java'nın Java'daki yığın üzerindeki tahsisinin C ++ 'dan daha hızlı olduğu için Java'daki her şeyin daha hızlı olduğunu iddia ediyorsunuz. İşte sizin için bazı haberler: C ++ ile birçok durumda yığın bellek ayırmadan yapabilirsiniz!
Sjoerd

10
@Sjoerd - Java'daki her şeyin daha hızlı olduğunu nereden söyledim ? Sadece söylediğimi oku. Ne demek istediğimi söyledim ve son yorumunda söylediğin her şeye zaten değindim.
Rex Kerr

49

Başlangıçta Java çok hızlı değildi, ama aşırı yavaş da değildi. Bugünlerde Java çok hızlı. Konuştuğum insanlardan Java'nın yavaş olduğu izlenimine iki şey geliyor:

  1. Yavaş VM başlatma zamanı. İlk Java uygulaması, yerel uygulamalara kıyasla gerekli kitaplıkları ve uygulamayı başlatmak ve yüklemek uzun zaman aldı.

  2. Yavaş kullanıcı arayüzü. Erken Salıncak yavaştı. Muhtemelen çoğu Windows kullanıcısının varsayılan Metal L&F'yi çirkin bulmasına yardımcı olmadı.

Yukarıdaki hususlar göz önüne alındığında, insanların 'Java yavaş' izlenimi edinmesi şaşırtıcı değildir.

Yerel uygulamalar ve hatta Visual Basic uygulamaları geliştirmek için kullanılan kullanıcılar veya geliştiriciler için , bu iki nokta bir uygulamadaki en görünür şeydir ve bir uygulama hakkında alacağınız ilk izlenimdir (GUI olmayan bir uygulama olmadığı sürece) yalnızca 1. durum geçerlidir.).

Uygulamayı başlatmak için 8 saniye sürdüğünde, kullanıcıyı hemen başlatan eski Visual Basic uygulamasına kıyasla - kod yürütme ve başlatma zamanı hiç bağlanmamış olsa bile, kullanıcıyı ikna edemezsiniz.

İlk izlenimi mahvetmek söylentilere ve mitlere başlamak için harika bir yoldur. Söylentileri ve mitleri öldürmek zor.

Kısacası, Java yavaş değildir. "Java yavaş tutumdur" olan insanlar 10 yıldan daha uzun bir süre önce ilk Java izlenimlerine dayanır.


3
Java birkaç yıl önce çok yavaştı, ancak son kıyaslama testlerinde neredeyse C / C ++ kadar hızlı çalışıyor ve bazı durumlarda daha hızlı çalışıyor.
ChadNC

23
Macbook'umdaki OSX 10.6'daki Java uygulamaları, Objective-C ile yazılmış uygulamalardan çok daha yavaş başlar. Hızlı başlatma süreleri için ne kanıt?
Zan Lynx

2
Dekompresyon kesinlikle bir performans sorunu değildir. 1992 yılındaki bilgisayarım, programları başlatırken sabit sürücüden daha uzun bir dosya yüklemeye kıyasla performansı artıran yürütülebilir dosyaları açmış. CPU ve sabit disk arasındaki eşitsizlik, aradan geçen yıllarda muazzam bir artış gösterdi. Ancak, rt.jar için zip arşiv biçimini kullanmayla ilgili bir sorun var (neden? !!!) ve içerdiği sınıf dosyaları bağlantılı değil (fındık !!).
Tom Hawtin - tackline

5
@Zan: Mac OS X için JVM'nin Apple tarafından yazıldığını (veya en azından uyarlandığını) unutmayın. Sun, destekledikleri platformlarda (Windows, Linux ve Solaris) başlatma sürelerini daha hızlı hale getirmek için biraz zaman harcadı, ancak Mac OS x için yapamadılar (bu bağlantı noktasını korumadıkları için). Mac, tüm bu optimizasyonları Mac OS X'e uygulayamadı / uygulayamadı /
taşıyamayabilir

1
Java'nın yavaş olduğunu düşünmüyorum (içlerinde oyun yapan bir oyun yapımcısı biliyorum); sadece kullanıcı arayüzü nedeniyle kötü. Gördüğüm tek bir "düzenli" java uygulaması iyi, tamamen çalışan bir kullanıcı arayüzü var.
RCIX

40

Java'nın yavaş olmadığını söyleyen yorumlarla dolu bir sayfayı okuduktan sonra, sadece farklı bir görüşle cevap vermem gerekiyor.

Bir dilin yavaşlığı, 'hızlı' beklentilerinizin ne olduğuna bağlıdır. C # 'ın hızlı olduğunu düşünüyorsanız, Java kesinlikle hızlıdır. Sorun alanınız veritabanları veya yarı gerçek zamanlı işleme ile ilgiliyse, Java da yeterince hızlıdır. Daha fazla donanım ekleyerek uygulamanızı ölçeklendirmekten memnunsanız, Java sizin için hızlıdır. 5-10 ölçeğinde sabit bir faktör hızının buna değmeyeceğini düşünüyorsanız, muhtemelen Java'yı hızlı düşünebilirsiniz.

Büyük veri kümelerinde sayısal hesaplama yaparsanız veya CPU kaynaklarının sınırlı olduğu, 5-10 ölçeğinde sabit bir hızın büyük olacağı bir yürütme ortamına bağlıysanız. 0,5 hızlanma bile hesaplamanın tamamlanması için 500 saatlik bir azalma anlamına gelebilir. Bu durumlarda, Java bu son performans alanını elde etmenize izin vermez ve muhtemelen Java'nın yavaş olduğunu düşünürsünüz.


2
kabul ettiniz ve geçerli bir nokta sunduğunuz için tüm yayında +1, ancak C ++, hata ayıklamak zor ve tüm bacağınızı havaya uçurmak için farklı bir şöhrete sahiptir, ancak nadiren C ++ 'ın o kadar yavaş olduğunu duydum java hakkında duyduğum gibi.
Stefano Borini

33

Oldukça farklı iki soru soruyorsunuz:

  1. Java gerçekten yavaş mı ve öyleyse neden?
  2. Java, birçok alternatiften daha hızlı olmasına rağmen neden yavaş olarak algılanıyor?

Bunlardan ilki aşağı yukarı “ipin ne kadar uzun” bir sorudur. "Yavaş" tanımınıza gelir. Saf bir tercümanla karşılaştırıldığında, Java son derece hızlıdır. (Normalde) bir çeşit bayt koduna derlenen ve daha sonra dinamik olarak makine koduna (örn. C # veya .NET'teki başka bir şey) derlenen diğer dillerle karşılaştırıldığında, Java kabaca eşittir. Normalde saf makine koduna derlenen dillerle karşılaştırıldığında ve (genellikle büyük), optimize edicilerini (ör. C, C ++, Fortran, Ada) geliştirmekten başka hiçbir şey üzerinde çalışmayan insan ekiplerine sahip olan Java, birkaç şeyde oldukça başarılıdır , ancak genel olarak en azından biraz daha yavaş olma eğilimindedir.

Bunların çoğu öncelikle uygulama ile ilgilidir - temel olarak, bir dinamik / JIT derleyicisi çalışırken bir kullanıcının beklediği gerçeğine gelir, bu nedenle başlamak için oldukça uzun bir süre çalışan bir programınız yoksa, derleyicinin zor optimizasyonlara çok zaman harcamasını haklı çıkarmak zor. Bu nedenle, çoğu Java (ve C # vb.) Derleyici gerçekten zor optimizasyonlar için çok çaba sarf etmez. Çoğu durumda, hangi optimizasyonların yapıldığı, uygulandıkları yerden daha azdır. Çoğu optimizasyon problemi NP tamamlanmıştır, bu nedenle aldıkları süre saldırıya uğrayan sorunun boyutuyla hızla büyür. Zamanı mantıklı tutmanın bir yolu, optimizasyonu aynı anda yalnızca tek bir işlev gibi bir şeye uygulamaktır. Derleyiciyi bekleyen yalnızca geliştirici olduğunda, çok daha uzun sürebilir ve aynı optimizasyonu programın daha büyük parçalarına uygulayabilirsiniz. Benzer şekilde, bazı optimizasyonların kodu oldukça tüylüdür (ve bu nedenle oldukça büyük olabilir). Yine, kullanıcı bu kod yüklenirken beklediğinden (ve JVM başlangıç ​​zamanı genellikle toplam süre için önemli bir faktördür), uygulama bir yerde kaydedilen zamanı diğerinde kaybolan zamanla dengelemek zorundadır ve ne kadar az kod verilirse tüylü optimizasyonlardan faydalanır, JVM'yi küçük tutmak genellikle daha faydalıdır.

İkinci bir sorun, Java ile sık sık daha fazla veya daha az "tek beden herkese uyar" türünde bir çözüm elde etmenizdir. Örneğin, birçok Java geliştiricisi için Swing aslında mevcut olan tek pencere kütüphanesidir. C ++ gibi bir şeyde, kelimenin tam anlamıyla düzinelerce pencere kütüphanesi, uygulama çerçevesi vb. Vardır; bunların her biri, kullanım kolaylığı ile hızlı yürütme, tutarlı görünüm ve his vs yerel görünüm ve his vb. Arasında kendi uzlaşma setlerine sahiptir. Tek gerçek yapışma noktası bazılarının (örneğin Qt) oldukça pahalı olabileceğidir (en azından ticari kullanım için).

Üçüncüsü C ++ (ve C daha da fazla) ile yazılmış bir sürü kod sadece daha eski ve daha olgun. Birçoğu, kodları optimize etmek için ekstra zaman harcamak normal, beklenen davranış olduğunda, on yıllar önce yazılmış bir rutin çekirdeği içerir. Bu genellikle kodda daha küçük ve daha hızlı gerçek bir yararı vardır. C ++ (veya C), kodun küçük ve hızlı olması için kredi alır, ancak gerçekten daha çok geliştiricinin bir ürünü ve kodun yazıldığı zamanın kısıtlamaları. Bir dereceye kadar, bu kendini gerçekleştiren bir kehanete yol açar - insanlar hızı önemsediğinde, genellikle bu şöhrete sahip olduğu için C ++ 'ı seçerler. Optimizasyona ekstra zaman ve çaba harcarlar ve yeni nesil hızlı C ++ kodu yazılır.

Özetlemek gerekirse, Java'nın normal uygulaması en iyi şekilde maksimum optimizasyonu sorunlu hale getirir. Daha da kötüsü, Java'nın görünür olduğu yerlerde , pencere araç takımları ve JVM başlangıç ​​zamanı gibi şeyler genellikle dilin yürütme hızından daha büyük bir rol oynar. Çoğu durumda, C ve C ++ aynı zamanda optimizasyonda daha çok çalışmanın ürünü için de kredi alır.

İkinci soruya gelince, bence bu büyük ölçüde işteki insan doğası meselesidir. Birkaç zealot Java'nın kör edici derecede hızlı olduğu konusunda oldukça şişirilmiş iddialarda bulunuyor. Birisi dener ve önemsiz bir programın bile başlaması birkaç saniye alır ve çalıştığında yavaş ve sakar hisseder. Çok azı, bunun büyük bir kısmının JVM'nin başlangıç ​​zamanı olduğunu ve şeyleri ilk denediğinde, kodun henüz derlenmediğini - kodun bazılarının yorumlandığını fark etmek için işleri analiz etmekle uğraşmaktadır. ve bazıları beklerken derleniyor. Daha da kötüsü, yeterince hızlı çalışsa bile, görünüm ve his çoğu kullanıcı için genellikle yabancı ve beceriksiz görünecektir, bu nedenle objektif ölçümler hızlı tepki süreleri gösterse bile, hala beceriksiz görünecektir.

Bunları bir araya getirmek oldukça basit ve doğal bir reaksiyona yol açar: Java'nın yavaş, çirkin ve sakar. Orada aşırı tepki eğilimi var ve olarak düşünmek sonuçlandıracaktır, hızlı gerçekten söyleyerek yutturmaca Verilen korkunç yerine (daha kesin) arasında yavaş "biraz daha yavaş ve çoğunlukla belirli koşulları altında." Bu genellikle dilde ilk birkaç programı yazan bir geliştirici için en kötüsüdür. Çoğu dilde "merhaba dünya" programının yürütülmesi anlık görünür, ancak Java'da JVM başlarken kolayca algılanabilir bir duraklama olur. Sıkı döngülerde çok daha yavaş çalışan saf bir yorumcu bile, böyle kod için genellikle daha hızlı görünecektir, çünkü sadece yüklenebilir ve biraz daha erken çalışmaya başlayabilir.


16

Java'nın ilk günlerinden (1990'ların ortalarından sonlarına kadar) eski bilgiler. Her büyük Java sürümü, önceki sürüme kıyasla önemli hız artışları sağlamıştır. Oracle görünüşe göre JRockit'i Sun'ın Java 7 için JVM'si ile birleştirirken, bu eğilim devam edecek gibi görünüyor.

Diğer birçok popüler modern dile (Python, Ruby, PHP) kıyasla, Java çoğu kullanım için gerçekten daha hızlıdır. C veya C ++ ile tam olarak eşleşmiyor, ancak birçok görev için yeterince yakın. Gerçek performans endişeleri, ne kadar bellek kullandığına dair olmalıdır.


14

"Uzun başlangıç ​​zamanı" ndaki ana suçlu dinamik bağlantıdır. Bir Java uygulaması derlenmiş sınıflardan oluşur. Her sınıf, diğer sınıflara (bağımsız değişken türleri, yöntem çağrıları ... için) ada göre başvurur . JVM, başlangıçta bu adları incelemeli ve eşleştirmelidir. Bunu kademeli olarak yapar, sadece herhangi bir zamanda ihtiyaç duyduğu parçaları yapar, ancak bu hala yapılması gereken bir iştir.

Bir C uygulamasında, bu bağlantı fazı derlemenin sonunda meydana gelir. Özellikle büyük uygulamalar için yavaştır, ancak yalnızca geliştirici bunu görür. Bağlama, işletim sisteminin RAM'i "olduğu gibi" yüklemesi gereken yürütülebilir bir dosya verir.

Java'da bağlantı, uygulamanın her çalıştırılışında gerçekleşir. Bu nedenle uzun başlatma süresi.

Önbellek teknikleri de dahil olmak üzere çeşitli optimizasyonlar uygulandı ve bilgisayarlar daha hızlı hale geliyor (ve uygulamalar "daha büyük" hale geldiklerinden "daha hızlı" oluyor), bu nedenle sorunun önemi son zamanlarda çok azaldı; ama eski önyargı devam ediyor.

Daha sonraki performansa gelince, dizi erişimli kompakt hesaplamalarda kendi kriterlerim (çoğunlukla karma işlevler ve diğer şifreleme algoritmaları) genellikle optimize edilmiş C kodunun Java kodundan yaklaşık 3 kat daha hızlı olduğunu gösterir; bazen C Java'dan sadece% 30 daha hızlıdır, bazen uygulanan algoritmaya bağlı olarak C 4 kat daha hızlı olabilir. İşlemcinin sunduğu 64x64-> 128 çarpma opodu nedeniyle "C" kodu aslında büyük tamsayı aritmetiği için birleştirildiğinde 10x faktörü gördüm, ancak Java en uzun tamsayı türü 64-bit olduğu için kullanamıyor long. Bu bir uç durum. Pratik koşullar altında, G / Ç ve bellek bant genişliği hususları C kodunun Java'dan gerçekten üç kat daha hızlı olmasını önler .


Hmm ... Çoğu C kütüphanesinin günümüzde de dinamik olarak bağlantılı olduğunu düşündüm. Yoksa farklı bir şeyden mi bahsediyorsunuz?
Sean McMillan

4
@Sean: C için dinamik bağlantı "harici semboller" için gerçekleşir: bir DLL'de kullanılan ve bir diğerinde tanımlanan işlevler. Tipik bir C uygulaması bir düzine DLL kullanır. Java için dinamik bağlantı, tüm sınıflardaki tüm yöntemler için gerçekleşir: tipik bir Java uygulamasında (standart kitaplık dahil) binlerce yöntem vardır . C dünyasında, bağlantıların çoğu (bir DLL sınırını geçmeyen tüm bağlantılar) derleme zamanında çözülür, çalışma zamanında yalnızca küçük bir oran hala kalır.
Thomas Pornin

14

Java, özellikle nicel çalışmalar için kesinlikle yavaştır.

Optimize edilmiş çok iş parçacıklı ATLAS kitaplıklarıyla R , Python ve C / C ++ birleşimini kullanıyorum . Bu dillerin her birinde yaklaşık 3000 saniyede 3000 ile 3000 çift matris matrisini yaklaşık 4 saniyede çarpabilirim. Java'da Colt ve Paralel Colt kullanarak aynı işlem 185 saniye sürer! Bu java kütüphanelerinin doğada paralel olmasına rağmen şaşırtıcı.

Sonuçta, saf Java nicel çalışmalar için uygun değildir. Jblas, ATLAS kullandığından Java için en iyi lineer cebir kütüphanesi gibi görünüyor.

Makinem 3 GB RAM'e sahip bir HP Core 2 Duo . 64-bit Ubuntu 10.04 (Lucid Lynx) kullanıyorum.


Yukarıda bahsettiğim yorumdan sonra, JAMA kullanarak aynı matris çarpma işlemini gerçekleştirdim ve yaklaşık 50 saniye sürdü. Diğer dillerle karşılaştırıldığında hala çok yavaş.
Hamaad Şah

7
JNI aracılığıyla çağrılan kütüphanelerde çarpma işlemi yaptığınızda Java ne kadar sürdü? C / C ++ 'da yapabileceğiniz herhangi bir şeyin JNI (birkaç yüz mnano-saniye ekleyin) ile yapabileceğiniz göz önüne alındığında, marj nispeten küçüktür. R ve Python matris çarpımınızın R veya Python'da yazılmadığını, sadece bu dillerden çağrıldığını tahmin ediyorum.
Peter Lawrey

2
Merakınız dışında, kodunuzda sıcak noktanızın olup olmadığını belirlemek için herhangi bir profil yaptınız mı (tip dönüşümü / otomatik kutulama)?
Thorbjørn Ravn Andersen

10

Onunla etkileşime çoğu insanın deneyimi için - Java olduğunu yavaş. Bazı uygulamaların ortaya çıkmasından önce kahve fincanının tarayıcımızda döndüğünü gördük. JVM'yi döndürmek ve uygulama ikili dosyalarını indirmek biraz zaman alır ve bu da kullanıcı deneyimini fark edilen bir şekilde etkiler.

Yavaş JVM spin-up ve applet indirme süresinin bir Java kahve fincanı ile dikkat çekici bir şekilde markalanması yardımcı olmaz, bu nedenle insanlar beklemeyi Java ile ilişkilendirir. Ne zaman Flaş yüke uzun zaman alır insanlar bir bütün olarak Flash teknolojisi suçlamıyorum yüzden, "yükleme" mesajının markalaşma, Flash geliştiricisi tarafından belirtilir.

Tüm bunların, Java'nın bir sunucudaki performansı veya Java'nın tarayıcı dışında kullanılması için başka birçok yolu yoktur. Ancak insanların gördükleri ve Java dışı geliştiricilerin Java hakkında düşündüklerinde hatırladıkları şey budur.


9

Java nedeniyle yavaş olma üne sahiptir oldu yavaş. Java'nın ilk sürümlerinde Just In Time derlemesi yoktu veya oldukça zayıftı. Bu, kodun bytecode olmasına rağmen yorumlandığı anlamına geliyordu, bu yüzden en basit işlemler için bile (iki tamsayı eklemek gibi) makinenin her türlü karşılaştırma ve işaretçi dereferences ve fonksiyon çağrıları yapmak zorunda kaldığı anlamına geliyordu. JIT derleyicisi sürekli gelişiyor; Şimdi C ++ kodunu dikkatsizce ve Java kodunu dikkatsizce yazarsam, Java bazen C ++ 'dan daha iyi performans gösterecektir, çünkü JIT derleyicisi bazı gereksiz işaretçi dereferencing'im olduğunu ve benim için ilgileneceğini fark eder.

JIT derlemesinin ne kadar büyük bir fark yarattığını görmek istiyorsanız, Bilgisayar Dilleri Karşılaştırma Oyunundaki yorumlanmış ve yorumlanmamış karşılaştırmalı değerlendirmelere bakın . (Pidigits, tüm hesaplamaları yapmak için harici bir kütüphane kullanır, böylece kıyaslama değişmez; diğerleri 6-16x hızlanma gösterir!)

Yani, ana sebep budur. Sorunlara yardımcı olmayan başka, daha az nedenler vardır: orijinal olarak, Java başlangıç ​​zamanı yavaştı (şimdi düzeltildi); Java'daki web uygulamalarının indirilmesi uzun zaman alıyor (şimdi geniş ölçüde erişilebilir geniş bant ve film gibi büyük şeyler bekleniyor); UI Swing, performans göz önünde bulundurularak yazılmadı (ve hala yazılmadı), bu nedenle örneğin C ++ 'daki eşdeğerlerden çok daha az çabuktur.


6

Java gün içinde yavaştı. Birkaç nesil performans geliştirmeleri nedeniyle çok daha hızlı hale geldi . En son duydum, genellikle C # hızının% 10'u içinde - bazen daha hızlı, bazen daha yavaş.

Java uygulamasının başlatılması hala yavaş çünkü tüm sınıflarını yüklemesi gereken bir JVM başlatmanız gerekiyor. Başka bir bilgisayarı önyükleme gibi. JVM başladıktan sonra oldukça hızlıdır, ancak başlangıç ​​genellikle insanların hatırladığı şeydir.

Ayrıca, Java'nın yaşayabilirliğine asla inanmayacak en az birkaç kişi var.


1
JVM'nin başlatılması maalesef CLR'nin başlatılmasından çok daha yavaş. Bunun nedeni Sun'ın Java 7'yi piyasaya
sürmek

3
Vay canına, Java 6 4 yaşında mı ??? Evet sanırım (beta'yı sayıyorsanız). Hala bana yeni geliyor - işte 1.4 kullanmayı bıraktım.
Kaleb Brasee

Java 1.4 kullanılabilir, ancak biraz emici, çünkü 1.5 ve 1.6 çok fazla performans artışı ve sözdizimsel şeker ekledi. O zamandan beri Bounds-check ve System.arraycopy optimizasyonları tanıtıldı. Bu yüzden birçok senkronizasyon iyileştirmesi yapıldı. Bence 1.4 gerçekten IS yavaş demek.
BobMcGee

LOL, biliyorum - el ile yineleme yapmak veya genel Liste yerine bir dizi kullanmak zorunda kaldığımda, dizüstü bilgisayarımı yarıya bölmek istiyorum ... IBM'in yıllardır WAS 6.1'de Java 5 mevcuttu, ancak ' WAS 6.0'da takılıp kaldım :( Java 5/6 kullanıyorum, çünkü kendi işlerim için çıktı, ancak işte eski sunucu sürümleri ile sınırlı kalıyorum. 1,4'ten en yeni sürüme kadar çift haneli yüzde performans iyileştirmeleri var ve dört gözle bekliyorum
Kaleb Brasee

6

Stefano:

Başından beri Java ile birlikteyim, bu yüzden yavaş olmanın şöhreti, yanıt vermeyen ve yavaş GUI ön uçları (AWT ve sonra Swing) tarafından oluşturuldu ve muhtemelen Applet'lerde muhtemelen ek yavaş başlatma süreleri nedeniyle VM en.

Java, VM alanında çok sayıda araştırmayı şart koştu ve teşvik etti ve çöp toplama (aslında birçok şeyi ayarlayabilirsiniz; ancak, genellikle yalnızca varsayılanların kullanıldığı sistemleri görüyorum) ve sıcak nokta da dahil olmak üzere bazı iyileştirmeler yapıldı. optimizasyon (başlangıçta ve muhtemelen sunucu tarafında daha verimlidir).

Java arka uç ve hesaplama düzeyinde o kadar yavaş değil. Colt en iyi örneklerden biridir:

En son kararlı Colt sürümü, JDK ibm-1.4.1, RedHat 9.0, 2x IntelXeon@2.8 GHz'deki 1.9 Gflop / s bariyerini ihlal ediyor.

Anaakım Java dışında, Gerçek Zamanlı Java veya Javolution gibi hızı artırmak için özel mekanizmaların yanı sıra Ahead-Of-Time derlemesi (gcj gibi) gibi düşünülmesi gereken birçok şey vardır . Ayrıca, Java Bytecode'u doğrudan çalıştırabilen IC'ler vardır, örneğin mevcut iPhone ve iPod ARM ARMelle'de olduğu gibi .

Genelde bugün siyasi bir karar (iPhone / iPod'da Java desteği yok gibi) ve Java'ya karşı dil olarak bir karar olduğunu düşünüyorum (çünkü birçoğu çok ayrıntılı olduğunu düşünüyor).

Bununla birlikte, günümüzde Java VM için alternatif olabilecek birçok dil (örn. Python, Ruby, JavaScript, Groovy, Scala vb.) Vardır.

Şahsen, en küçük cihazdan (örneğin JavaCard) en büyük sunuculara kadar her şeyle çalışmasına izin veren mükemmel takım ve kütüphane kullanılabilirliğine sahip esnek ve güvenilir bir platform olarak keyfini çıkarmaya devam ediyorum.


Tamam, GUI araç setinden başka bir kötü şöhret geldi. Elbette, modern JVM'nin yerel widget'ları kullandığından, OS kütüphanelerine bağlandıklarını varsayıyorum, değil mi? veya ana platformla aynı görünümü ve hissi vermek için AWT / Swing kullanıyorlar mı?
Stefano Borini

Stefano: Swing aslında widget'ların yerli olmayan evrensel oluşturulması fikrine dayanıyor, bu yüzden varsayımınız biraz yanlış. Gerçekten de, Swing bileşenlerinin doğal bileşenlerin görünümünü taklit etmesini sağlayan "takılabilir bir görünüm ve his" mekanizmasıdır. Böyle bir şey arıyorsanız , aslında yerel işletim sistemine bağlanacak ve JNI (bir darboğaz olduğu söylenir) kullanarak yerel widget'ları kullanacak olan SWT'ye ( eclipse.org/swt ) göz atmak isteyebilirsiniz .
Dieter

Java2D (Swing için kullanılır) bu günlerde çok hızlıdır ve yerel widget'ları (SWT) kullanmak hiçbir performans avantajı sağlamaz. En azından, 6 ay önce Swing veya SWT öğrenmeye karar verirken okuduğum şey bu.
Luigi Plinge

4

Çekiç, hamuru açarken diğer birçok aletten çok daha yavaştır. Çekiciyi "daha yavaş" yapmaz veya yapmak için tasarlandığı görevler için daha az kullanışlı hale getirmez.

Genel bir programlama dili olarak Java, geniş bir programlama görevleri dizisi için (çoğu değilse) eşittir. Java'nın "metale daha yakın" olan daha az karmaşık dillerde el kodlu çözümlerden daha iyi performans göstermeyeceği özel, önemsiz testler vardır.

Ancak "gerçek dünya uygulamaları" söz konusu olduğunda, Java genellikle Doğru Araç'tır. Şimdi, hiçbir şey geliştiricilerin HERHANGİ bir araç kullanarak yavaş performans gösteren bir çözüm yapmasını engelleyemez. Aracın yanlış kullanımı iyi bilinen bir sorundur (sadece PHP ve VB'nin itibarlarına bakın). Ancak, Java'nın (çoğunlukla) temiz tasarımı ve sözdizimi yanlış kullanımı azaltmak için çok şey yapar.


3

Java üst düzey bir dildir ve günümüzde itibarı diğer karşılaştırılabilir üst düzey dillerle aynı performansa sahip olmaktır.

  1. It has dinamik bağlama anlambilim. Sanal olmayan yöntemlerin işlev çağrısı olarak derlendiği C ++ ile karşılaştırıldığında, dünyadaki en iyi Java derleyicisinin bile daha az verimli kod üretmesi gerekir. Ama aynı zamanda daha temiz, daha üst düzey bir anlambilimdir.

  2. Ayrıntıları hatırlamıyorum, ancak Java'nın ilk günlerinde her bir nesne tarafından edinilecek ve serbest bırakılacak bir Java nesnesi başına bir muteks olduğunu duydum. Maalesef sadece nesne başına bir muteks sizi yarışlardan veya kilitlenmelerden veya eşzamanlı programlarda olabilecek kötü şeylerden koruyamayacak olsa da, eşzamanlılığa daha iyi adapte olma eğilimindedir. Bu kısım, eğer doğruysa, biraz saftır, ama iyi niyetlerden geldi. Bu yön hakkında daha fazla bilgi sahibi olursanız bana ayrıntıları doldurmaktan çekinmeyin.

  3. Java'nın üst düzey bir dil olduğu başka bir yol da Garbage-Collection'a sahip olmaktır . Çöp-Toplama daha yavaş olabilir mallocve freebununla tüm ihtiyaç duydukları bellek ve işin bir defada tahsis programlar için. Sorun şu ki, Çöp Toplama özelliği olmayan dillerde, programcılar yalnızca ihtiyaç duydukları tüm belleği bir kerede tahsis eden ve rasgele bir maksimum boyut sabiti taşmışsa başarısız olan programlar yazma eğilimindedir . Yani elma ile portakal karşılaştırması. Programcılar, GC olmayan dillerde zincirleme yapıların dinamik tahsisi ile programlar yazmak ve hata ayıklamak için çaba harcadıklarında, bazen programlarının bir GC dilinde olduğundan daha hızlı olmadığını görürler, çünkümalloc vefreeözgür değil! Ayrıca yükleri de var ... Ayrıca, kimin neyi serbest bıraktığını belirtmek için bir GC kuvveti olmamak ve bazen kimin neyi serbest bıraktığını belirlemek zorunda kalmak, bazen birkaç işlev veriye ihtiyaç duyacağı ve bir GC dilinde kopyalamaya gerek kalmayacak.


1. HotSpot ile muhtemelen doğru değil. 2. Yalnızca yöntemi senkronize olarak işaretlerseniz.
Winston Ewert

1
1. Derleyici kodu optimize etmez, ancak JVM genellikle yalnızca bir veya iki sanal yöntemin çağrıldığını dinamik olarak belirleyecek kadar akıllıdır ve bunları statik veya hatta satır içi olarak çağırabilir. C ++ sanal yöntemleri satır içi edemez eminim. 2. Her Java Nesnesinin bir kilidi vardır. Her nesne üzerinde küçük bir yük (yaklaşık bir bayt) vardır, ancak kullanılmazsa çok az etkisi vardır. 3. Java'da ihtiyacınız olan tüm Nesneleri bir kerede tahsis edebilirsiniz. Bu size bütün gün GC olmayan bir uygulama verebilir. ;) Java'nın GC'si dolaylı olarak çok iş parçacıklı, C ++ 'da özel kütüphaneler gerektiren bir şey.
Peter Lawrey

C ++ sanal aramaları sıralayabilir, ancak Java bunu daha fazla durumda yapabilir ve ayrıca megamorfik arama sitelerini optimize etmede daha güçlüdür.
Piotr Kołaczkowski

2

Doksanların ortalarında Java ana akıma girdiğinde, C ++ baskın dildi ve web hala oldukça yeniydi. Ayrıca JVM'ler ve GC ana akım gelişiminde nispeten yeni kavramlardı. İlk JVM'ler biraz yavaştı (çıplak metal üzerinde çalışan C ++ ile karşılaştırıldığında) ve ayrıca bazen uzun çöp toplama duraklamalarından muzdaripti, bu da Java'nın itibarının yavaş olmasına neden oldu.


bunun nedeni GC'nin arkasındaki teknoloji miydi? GC aşamasında daha verimli olmaları için bazı stratejileri (nesneler için nesil katmanları gibi) olduğunu biliyorum. O sırada strateji neydi?
Stefano Borini

1
IANA JVM uzmanı, ancak o zaman GC için kullanılan tek bir dişli işaret / süpürme algoritması olduğunu düşünüyorum, bu GC yapılırken tüm JVM'nin duraklamasını gerektiriyordu. Günümüzde eşzamanlı işaret / süpürme ve ayrıca JVM'de başka birçok performans geliştirmesi var.
Ken Liu

2
Modern GC algoritmaları güzel ama en büyük gelişmenin JIT olduğunu düşünüyorum.
Pascal Thivent

1

Çoğu Java masaüstü uygulaması (bu kez: Eclipse gibi şeyler), muhtemelen yüksek bellek tüketimi ve sınıf yükleyicinin çok fazla IO yapabilmesi nedeniyle GUI yanıt hızına sahiptir. Gelişiyor ama birkaç yıl önce daha kötüydü.

Çoğu (çoğu) kişi genellemeler yapmayı sever, böylece "Java yavaştır" derler çünkü uygulamalarla etkileşime girdiklerinde yavaş olduklarını algılarlar.


yüksek bellek tüketiminin araçtan mı yoksa java kütüphanelerinden mi geldiğini düşünüyor musunuz?
Stefano Borini

Eclipse durumunda - Eclipse altyapısının kendisinden. Geçmişte "ağır" GUI'ler için aynı (hatırladığım kadarıyla JBuilder). Ben statik bir şekilde yazılan bir dilde bir eklenti mimarisi (Eclipse gibi) kullanmak için gerekli olan boilerplate nesneleri bir sürü çünkü bir bağırsak hissi var. Emacs'ın da eklentileri vardır ve tipik kodlama yaparken bellek tüketimi Eclipse'den 10-20x daha azdır. Emacs Lisp kodu bayt koduna derlenir ve emacs örneğine yüklenir, ardından çalıştırılır - Java sınıf yükleyicisine benzer. Java'da bazı eklentilere izin vermek için somutlaştırılmış tonlarca ara nesne var sanırım.
Wojciech Kaczmarek

1

Java uygulamaları ile büyük sorunu olmasıdır kocaman nedeniyle stok çalışma zamanı kütüphanesinin büyük bir boyuta. Büyük programlar hafızayı çok doldurur ve takas etme eğilimindedir, yani yavaşlarlar.

Sun JVM'nin büyük olmasının nedeni, birçok şeyi takip ederek çalışan çok iyi bir bayt kodu yorumlayıcısına sahip olmasıdır. Bu çok fazla veri demek, yani hafıza demek.

Oldukça hızlı bir tercüman (yerel kod yok) ve çok küçük olan jamvm sanal makinesine bakmak isteyebilirsiniz. Hatta hızlı başlar.


1

Pascal'ın dediği gibi, Java diğer üst düzey dillerle eşittir. Bununla birlikte, Windows 98'de orijinal JVM'lerle çalışan biri olarak , Java sanal makinesi tarafından sağlanan soyutlama seviyesi acı verici idi.

Temel olarak, bugün JVM'de verdiğimiz optimizasyonun çok az olduğu veya hiç olmadığı bir yazılım öykünmesiydi.


0

İnsanlar normalde “yorumlanır” çizgisini tırmandılar. Çünkü bir zamanlar öyleydi, ve kötü basın, Java'yı 'çok yavaş' olarak terk eden ve daha yeni sürümleri test etmek için geri dönmeyen insanlar tarafından dağıtılır.

Ya da belki "insanlar aptallardır" daha iyi bir cevaptır.


0

Sanırım bir gün, belki çok yakın gelecekte değil, JIT derlenmiş diller, JIT derleyicilerinin çalışma süresini yoğun şekilde kullanabilmeleri nedeniyle derlenmiş dillerden herhangi bir açıdan daha iyi performans gösterecektir (belki başlangıç ​​zamanı / bellek tüketimi değil). davranışları ve üzerinde çalıştıkları platform.


6
Ne demek istediğini JIT derlenmiş (yorumlanmadı) kodu AoT kodu yenecek olduğunu düşünüyorum. Yorum her zaman derlenmiş kodu çalıştırmaktan daha yavaş olacaktır. Bu yüzden JIT derleyicileri kullanılır. Yakalama: bir JIT derleyicisinin daha hızlı bir şekilde derlenmesi ve optimizasyonlarını ipucu için çalışma zamanı bilgisini kullanabilmesi dışında, vaktinden önce bir derleyici ile JIT derleyicisi arasında çıkış açısından çok az fark vardır. Platforma özgü optimizasyonlara sahip platforma özgü AoT derleyicileri neredeyse her zaman JIT'i yener çünkü optimizasyon için ne kadar zaman harcadıklarına dair bir sınır yoktur.
BobMcGee

Cevabınız için teşekkürler, JIT derleyicilerinin elindeki az zamanı düşünmedim.
Ocak'ta helpermethod

yani etkin nokta uyarlamalı optimizasyon gibi bir şey mi?
Stefano Borini

2
@BobMcGee: Çok doğru. Bir C ++ programı, tüm işlemleri için profil geri bildirimi ile yavaş çalışacak şekilde oluşturulabilir. Daha sonra derleyici, yarım saatlik CPU süresi ve 2 GB RAM kullanarak çok hızlı bir sürümü yeniden oluşturmakta serbesttir. Bunu yapan bir JIT, kullanıcıların ayrılmasını sağlayacaktır.
Zan Lynx

1
JIT derleme süresi, sunucular gibi uzun süre çalışan uygulamalar için önemsizdir. AGO ile AOT, en az 2 nedenden ötürü JIT ile karşılaştırıldığında daha sınırlıdır. İlk olarak, çoğu performans farkı hafif optimizasyonlarla elde edilir. Gcc -O2 ile gcc -O3'ü karşılaştırın. Çoğu zaman bir fark yoktur , bazen -O3 biraz daha iyi, bazen biraz daha kötü olabilir, ancak bundan 2 kat daha fazla bir fark yaşamadım. İkincisi, PGO ile bile AOT kullanarak sadece profilin kullanım yerinde ne olacağını tahmin edebilirsiniz. Sanırım yanlış, ve JIT'in çok gerisindesiniz. Ve gerçek profil son derece konfigürasyona bağlı olabilir.
Piotr Kołaczkowski
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.