Kafayı yiyecektim arkadaşlar. Performans kritik bir backend servisi yazıyordum, her şey güllük gülistanlık gibiydi. Ta ki, milyonlarca tamsayıyı ArrayList<Integer> ile tutmaya kalkana kadar. JVM'in hafıza tüketimi resmen roket gibi fırladı! Meğerse sorun, o masum gibi görünen `ArrayList<Integer>`'ın içinde saklanan her bir int'in, bir Integer objesine dönüşmesiymiş. Şaka gibi ama, bu "autoboxing" denen olay, heap'e gizli bir saldırı başlatıyor.
Boxing'in Maliyeti: Primitive vs Wrapper
Düşünün, basit bir `int` sadece 4 byte yer kaplar. Ama onu `ArrayList<Integer>`'a eklediğiniz an, Java arka planda `Integer.valueOf()` çağırır ve o 4 byte'lık değer, kocaman bir nesneye dönüşür. Bu Integer objesi, kendi başlığı (header) ve referansıyla birlikte, 16 byte civarı bir yer yutar! Yani hafıza kullanımı neredeyse 4 KAT artar. Milyonlarca eleman için bunu hesaplayın, sonuç felaket.
Profilörle Yakaladığım Facia
VisualVM ile profili aldığımda, Integer sınıfından milyonlarca instance'ın heap'i doldurduğunu gördüm. Her biri ayrı bir obje, ayrı bir referans... GC (Çöp Toplayıcı) deli gibi çalışıp duruyordu, sürekli minor GC'ler oluyordu. Performansın düşmesinin asıl sebebi buydu. StackOverflow'da bile "ArrayList performansı" diye ararken, bu kadar net bir şekilde "boxing maliyeti"ne odaklanan bir yanıt bulamamıştım.
Çözüm Yolu: `int[]` veya Özel Kütüphaneler
Peki ne yaptım? Eğer boyut belli ve sabitse, direkt int[] dizisine geçiş yaptım. Hafıza ve erişim hızı inanılmaz arttı. Boyut dinamikse ve List arayüzüne ihtiyacım varsa, Trove kütüphanesindeki TIntArrayList gibi primitive'leri doğrudan tutan yapıları araştırmaya başladım. Bu kütüphaneler, Integer objesi yaratmadan, doğrudan `int` değerlerini saklayarak heap'teki bu gizli saldırıyı bertaraf ediyor.
Kodu optimize ederken en büyük derslerden birini aldım: Kolay yazılan kod, her zaman verimli çalışmaz. Özellikle koleksiyonlarla çalışırken, içinde ne sakladığınızı ve Java'nın arka planda sizin için ne yaptığını çok iyi bilmek gerekiyor.
Siz de böyle bir "autoboxing" tuzağına düştünüz mü? Özellikle büyük veri setleriyle çalışırken, primitive koleksiyonlar için hangi çözümleri tercih ediyorsunuz? `ArrayList<Integer>`'ın bu maliyetini göz ardı eden oldu mu aranızda?
Düşünün, basit bir `int` sadece 4 byte yer kaplar. Ama onu `ArrayList<Integer>`'a eklediğiniz an, Java arka planda `Integer.valueOf()` çağırır ve o 4 byte'lık değer, kocaman bir nesneye dönüşür. Bu Integer objesi, kendi başlığı (header) ve referansıyla birlikte, 16 byte civarı bir yer yutar! Yani hafıza kullanımı neredeyse 4 KAT artar. Milyonlarca eleman için bunu hesaplayın, sonuç felaket.
Java:
// Görünüşte masum:
ArrayList<Integer> sayilar = new ArrayList<>();
sayilar.add(42); // Burada 42, Integer objesine "box"lanıyor!
// Aslında olan:
sayilar.add(Integer.valueOf(42)); // İşte gizli maliyet!
VisualVM ile profili aldığımda, Integer sınıfından milyonlarca instance'ın heap'i doldurduğunu gördüm. Her biri ayrı bir obje, ayrı bir referans... GC (Çöp Toplayıcı) deli gibi çalışıp duruyordu, sürekli minor GC'ler oluyordu. Performansın düşmesinin asıl sebebi buydu. StackOverflow'da bile "ArrayList performansı" diye ararken, bu kadar net bir şekilde "boxing maliyeti"ne odaklanan bir yanıt bulamamıştım.
Peki ne yaptım? Eğer boyut belli ve sabitse, direkt int[] dizisine geçiş yaptım. Hafıza ve erişim hızı inanılmaz arttı. Boyut dinamikse ve List arayüzüne ihtiyacım varsa, Trove kütüphanesindeki TIntArrayList gibi primitive'leri doğrudan tutan yapıları araştırmaya başladım. Bu kütüphaneler, Integer objesi yaratmadan, doğrudan `int` değerlerini saklayarak heap'teki bu gizli saldırıyı bertaraf ediyor.
Kodu optimize ederken en büyük derslerden birini aldım: Kolay yazılan kod, her zaman verimli çalışmaz. Özellikle koleksiyonlarla çalışırken, içinde ne sakladığınızı ve Java'nın arka planda sizin için ne yaptığını çok iyi bilmek gerekiyor.
Siz de böyle bir "autoboxing" tuzağına düştünüz mü? Özellikle büyük veri setleriyle çalışırken, primitive koleksiyonlar için hangi çözümleri tercih ediyorsunuz? `ArrayList<Integer>`'ın bu maliyetini göz ardı eden oldu mu aranızda?