String.substring() ilginçliği
Benim de geçenlerde şuradaki bir blog yazısından öğrendiğim String sınıfının substring() metodu ile ilgili ilginç bir durumdan bahsedeyim. Yazacaklarımın çoğu çeviri değerinde.
String a = “abcdefgh”;
a = a.substring(0,3);
şeklinde bir kod ile başlangıçta oluşturduğumuz String tipinde a nesnesinin ilk 3 karakterini ayrıştırıp yine kendisine atamış oluyoruz. Oluşan nesne yeni bir String nesnesidir. Çünkü String değişmez(immutable) bir tiptir. Bir kez oluşturulduktan sonra değişmezler yani. Integer, Double gibi ilkel tipleri sarmalayan tipler de öyledirler.
String nesnesinde;
value; char[] tipinde bir deÄŸiÅŸken. String nesnesinde bulunan karakterleri tutuyor.
count;int tipinde bir değişken. String nesnesinde bulunan karakter sayısını tutuyor.
offset;int tipinde bir deÄŸiÅŸken. String nesnesinin ilk karakterinin indeksini tutuyor.
ÅŸeklinde 3 alan bulunuyor.
substring() iÅŸlemi ile char[] dizisi (value) yeni oluÅŸan String nesnesine doÄŸrudan kopyalanıyor. Fakat count ve offset alanlarına uygun karşılıkları atanıyor. Dolayısıyla a nesnesini System.out.print(a); ÅŸeklinde konsola yazdıracak olursak “abc” deÄŸerlerini görüyoruz. Garip olan ÅŸu ki Reflection ile a nesnesinin sahip olduÄŸu karakter dizisine ulaÅŸtığımızda gördüğümüz deÄŸer “abcdefgh”. (Reflection ile nasıl nesnenin gerçek “value” deÄŸerini gördüğümüzün çok önemi olmadığı için kod örneÄŸini yazmaya gerek yok hani). Buradan oluÅŸan yeni String nesnesinin count ve offset deÄŸerleri farklı olsa da karakter dizisinin birebir kopya olduÄŸunu anlıyoruz. Örnek koda ÅŸuradan bakılabilir.
Bu durum hafıza kullanımında gereksiz şişmelere yol açabiliyor. Özellikle de sık sık substring() metotu ile büyük String nesneleri ayrıştıran bir işlem varsa. Yeri gelmişken bir String nesnesinin hafızada ne kadar yer kapladığını da şu şekilde hesaplıyoruz.
Yukarıda bahsettiÄŸimiz int tipinde count ve offset deÄŸiÅŸkenlere ilave olarak bir de hashCode için int tipinde bir deÄŸiÅŸken tutuluyor. Bu 3 int tipindeki deÄŸiÅŸken 4’er baytdan 12 bayt, nesnenin “object header” denen kimlik bilgisi de 8 bayt yer kaplıyor. BoÅŸ karakter dizisi olan char[] deÄŸiÅŸkeni de 8 bayt karater dizisi, 4 bayt dizinin uzunluÄŸunu tutmak için bulunan deÄŸiÅŸken, ve 4 bayt da toplamda 16’nın 12’ye en yakın katı olan 16’ya tamamlamak için olmak üzere; 16 bayt yer kaplıyor. 12+8+16=36’yı da bir sonraki 8’in katı olan 40’a tamamlıyoruz. Bu da boÅŸ bir String nesnesinin 40 bayt yer kapladığını gösteriyor.
Kabaca şöyle bir formül çıkıyor;
– String nesnesinde bulunan karakter sayısını iki ile çarp,
– 38 ekle,
– Sonuç 8’in katı bir sayı deÄŸilse sonraki ilk 8’in katı olan sayıya yuvarla
20 karakter içeren bir String nesnesi;
20*2 = 40,
40+38=78,
78’i de 8’in sonraki ilk katına tamamlarsak ->80 bayt yer kaplıyor
Mevzuya dönecek olursak bu gibi hafıza şişmelerini engellemek için substring() metodundan dönen String nesnesini yine bir String nesnesinin yapılandırıcısına parametre olarak geçiyoruz.
String a = new String(a.substring(0,3));
Bu arada aynı durum String sınıfının trim() metodu için de geçerli. Farkında olmaya değer bir ilginçlik.
Son Yorumlar