paint-brush
Yazılım, Siz Önce Onu Öldürmediğiniz Sürece Büyür: Erken Optimizasyon ve Bir Java GC Hikayesiile@wasteofserver
553 okumalar
553 okumalar

Yazılım, Siz Önce Onu Öldürmediğiniz Sürece Büyür: Erken Optimizasyon ve Bir Java GC Hikayesi

ile Frankie6m2024/04/06
Read on Terminal Reader

Çok uzun; Okumak

Optimizasyonlarla aşırıya kaçmayın, bırakın dil sizin için çalışsın. Hikaye anlat. Java yükseltmeleri ücretsiz olarak performans artışı sağlar. Her zaman kıyaslama yapın.
featured image - Yazılım, Siz Önce Onu Öldürmediğiniz Sürece Büyür: Erken Optimizasyon ve Bir Java GC Hikayesi
Frankie HackerNoon profile picture
0-item

LinkedList daha hızlı olacak mı? 'Her biri için' ifadesini bir 'yineleyici' ile değiştirmeli miyim? Bu 'ArrayList' bir 'Array' mi olmalı? Bu makale o kadar kötü niyetli bir optimizasyona yanıt olarak geldi ki, hafızama kalıcı olarak kazındı.


Java'ya ve çöp toplayıcıdan ya da bağlam değiştirmeden kaynaklanan parazitlerle başa çıkmanın yollarına girmeden önce, ilk olarak gelecekteki kendiniz için kod yazmanın temellerine bir göz atalım.


Erken optimizasyon tüm kötülüklerin köküdür.


Bunu daha önce duymuştunuz; Erken optimizasyon tüm kötülüklerin köküdür. Bazen. Yazılım yazarken şunlara kesinlikle inanıyorum:


  1. mümkün olduğunca açıklayıcı ; hikaye yazıyormuş gibi niyetleri anlatmaya çalışmalısınız.


  2. mümkün olduğu kadar optimal ; bu da dilin temellerini bilmeniz ve buna göre uygulamanız gerektiği anlamına gelir.

Olabildiğince Açıklayıcı

Kodunuz amacı ifade etmelidir ve bunların büyük bir kısmı, yöntemleri ve değişkenleri adlandırma şeklinizle ilgilidir.


 int[10] array1; // bad int[10] numItems; // better int[10] backPackItems; // great

Yalnızca değişken adından zaten işlevsellik sonucunu çıkarabilirsiniz.


numItems soyut olsa da backPackItems size beklenen davranış hakkında çok şey anlatır.


Veya bu yönteme sahip olduğunuzu söyleyin:


 List<Countries> visitedCountries() { if(noCountryVisitedYet) return new ArrayList<>(0); } // (...) return listOfVisitedCountries; }

Kod söz konusu olduğunda, bu aşağı yukarı iyi görünüyor.


Daha iyisini yapabilir miyiz? Kesinlikle yapabiliriz!


 List<Countries> visitedCountries() { if(noCountryVisitedYet) return Collections.emptyList(); } // (...) return listOfVisitedCountries; }

Collections.emptyList() i okumak new ArrayList<>(0); 'dan çok daha açıklayıcıdır.


Yukarıdaki kodu ilk kez okuduğunuzu ve kullanıcının ülkeleri gerçekten ziyaret edip etmediğini kontrol eden koruma maddesine rastladığınızı hayal edin. Ayrıca, bunun uzun bir sınıfa gömüldüğünü hayal edin, Collections.emptyList() okumak kesinlikle new ArrayList<>(0) okumaktan daha açıklayıcıdır, ayrıca müşteri kodunun onu değiştiremeyeceğinden emin olarak bunun değişmez olduğundan da emin olursunuz.

Mümkün Olduğunca Optimum

Dilinizi bilin ve ona göre kullanın. Bir double ihtiyacınız varsa, onu bir Double nesnesine sarmanıza gerek yoktur. Eğer gerçekten ihtiyacınız olan tek şey Array ise aynı durum List kullanımı için de geçerlidir.


İş parçacıkları arasında durumu paylaşıyorsanız, StringBuilder veya StringBuffer kullanarak Dizeleri birleştirmeniz gerektiğini bilin:


 // don't do this String votesByCounty = ""; for (County county : counties) { votesByCounty += county.toString(); } // do this instead StringBuilder votesByCounty = new StringBuilder(); for (County county : counties) { votesByCounty.append(county.toString()); }


Veritabanınızı nasıl indeksleyeceğinizi bilin. Darboğazları önceden tahmin edin ve buna göre önbellekleyin. Yukarıdakilerin tümü optimizasyonlardır. Bunlar, ilk vatandaşlar olarak bilmeniz ve uygulamanız gereken türden optimizasyonlardır.

İlk Önce Nasıl Öldürürsünüz?

Birkaç yıl önce okuduğum bir hack'i asla unutmayacağım. Gerçeği söylemek gerekirse yazar hızla geri adım attı ama bu, iyi niyetlerden ne kadar çok kötülüğün kaynaklanabileceğini gösteriyor.


 // do not do this, ever! int i = 0; while (i<10000000) { // business logic if (i % 3000 == 0) { //prevent long gc try { Thread.sleep(0); } catch (Ignored e) { } } }

Cehennemden gelen bir çöp toplayıcı hack'i!


Yukarıdaki kodun neden ve nasıl çalıştığı hakkında daha fazla bilgiyi orijinal makalede okuyabilirsiniz ve bu istismar kesinlikle ilginç olsa da, bu asla yapmamanız gereken şeylerden biridir.


  • Yan etkilerle çalışır, Thread.sleep(0) ın bu blokta hiçbir amacı yoktur
  • Aşağı yöndeki kod eksikliğinden yararlanarak çalışır
  • Bu kodu miras alan herkes için bu gizemli ve büyülüdür.


Dilin sağladığı tüm varsayılan optimizasyonlarla yazdıktan sonra bir darboğazla karşılaşırsanız, biraz daha karmaşık bir şey oluşturmaya başlayın. Ancak yukarıdaki gibi karışımlardan uzak durun.


Java'nın gelecekteki Çöp Toplayıcısının Microsoft Copilot tarafından "hayal edilen" bir yorumu


Çöp Toplayıcıyla Nasıl Başa Çıkılır?

Her şey bittiğinde, Çöp Toplayıcı hâlâ direnç sunan parçaysa deneyebileceğiniz şeylerden bazıları şunlardır:


  • Hizmetiniz GC'ye izin veremeyecek kadar gecikmeye duyarlıysa, "Epsilon GC" ile çalıştırın ve GC'den tamamen kaçının .
    -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC


    Bu, bir OOM istisnası elde edene kadar belleğinizi açıkça büyütecektir, yani bu ya kısa ömürlü bir senaryodur ya da programınız nesneler oluşturmayacak şekilde optimize edilmiştir


  • Hizmetiniz gecikmeye biraz duyarlıysa ancak izin verilen tolerans bir miktar hareket alanına izin veriyorsa , GC1'i çalıştırın ve -XX:MaxGCPauseTimeMillis=100 gibi bir şey besleyin (varsayılan 250 ms'dir)

  • Sorun harici kütüphanelerden kaynaklanıyorsa , diyelim ki bunlardan biri dünyayı durduran çöp toplayıcıları System.gc() veya Runtime.getRuntime().gc() yi çağırıyor, -XX:+DisableExplicitGC ile çalıştırarak rahatsız edici davranışları geçersiz kılabilirsiniz. -XX:+DisableExplicitGC



VERSİYON BAŞLANGICI

VERSİYON SONU

VARSAYILAN GC

Java 1

Java4

Seri Çöp Toplayıcı

Java 5

Java 8

Paralel Çöp Toplayıcı

Java 9

devam ediyor

G1 Çöp Toplayıcı


Not 1: Java 15'ten beri ZGC üretime hazırdır , ancak yine de onu -XX:+UseZGC ile açıkça etkinleştirmeniz gerekir.


Not 2: VM, ikiden fazla işlemci ve yığın boyutunun 1792 MB'a eşit veya daha büyük olduğunu tespit ederse, makineleri sunucu sınıfı olarak kabul eder. Sunucu sınıfı değilse, varsayılan olarak Serial GC olacaktır .


Temel olarak, uygulamanın performans kısıtlamalarının doğrudan çöp toplama davranışına bağlı olduğu açık olduğunda ve bilinçli ayarlamalar yapmak için gerekli uzmanlığa sahip olduğunuzda GC ayarlamasını tercih edin. Aksi takdirde, JVM'nin varsayılan ayarlarına güvenin ve uygulama düzeyindeki kodu optimize etmeye odaklanın.

u/shiphe - yorumun tamamını okumak isteyeceksiniz


Keşfetmek İsteyebileceğiniz Diğer İlgili Kütüphaneler:

Java Mikro Karşılaştırma Demeti (JMH)

Gerçek bir kıyaslama olmadan duyguyu optimize ediyorsanız, kendinize kötülük yapıyorsunuz demektir. JMH, algoritmalarınızın performansını test etmek için kullanılan fiili Java kütüphanesidir. Kullan onu.

Java-İş Parçacığı Yakınlığı

Bir işlemi belirli bir çekirdeğe sabitlemek önbellek isabetlerini iyileştirebilir. Bu, temeldeki donanıma ve rutininizin verilerle nasıl başa çıktığına bağlı olacaktır. Bununla birlikte, bu kitaplık uygulamayı o kadar kolaylaştırır ki, yoğun CPU kullanan bir yöntem sizi zorluyorsa, onu test etmek isteyeceksiniz.

LMAX Engelleyici

Bu, ihtiyacınız olmasa bile çalışmak isteyeceğiniz kütüphanelerden biri. Buradaki fikir, ultra düşük gecikme süreli eşzamanlılığa izin vermektir. Ancak mekanik sempatiden halka tamponuna kadar uygulanma şekli birçok yeni konsepti beraberinde getiriyor. Yedi yıl önce onu ilk keşfettiğim zamanı, onu sindirmek için bütün geceyi geçirdiğimi hâlâ hatırlıyorum.

Netflix jvmquake

jvmquake temeli, JVM'de işler ters gittiğinde onun ölmesini ve takılmamasını istemenizdir. Birkaç yıl önce, sıkı bellek kısıtlamalarına sahip bir HTCondor kümesi üzerinde simülasyonlar çalıştırıyordum ve bazen işler "bellek yetersiz" hataları nedeniyle takılıp kalıyordu.


Bu kütüphane JVM'yi ölmeye zorlayarak gerçek hatayla başa çıkmanıza olanak tanır. Bu özel durumda, HTCondor işi otomatik olarak yeniden planlayacaktır.

Son düşünceler

Bu yazıyı yazmamı sağlayan kod? Çok daha kötülerini yazdım. Hala yapıyorum. Umabileceğimiz en iyi şey sürekli olarak daha az karışıklık yaratmaktır.


Birkaç yıl sonra kendi koduma baktığımda hoşnutsuz olmayı bekliyorum.


Ve bu iyi bir işaret.



Düzenlemeler ve Teşekkür Ederiz:


Wasteofserver.com'da da yayınlandı