Java'da String Pool Konsepti

Java'da String Pool Konsepti

    

    Java programlama dilinde String veri tipi, çift tırnak içerisine yazılmış karakterler dizisi olarak tanımlanır. Aşağıda en basit haliyle bir String tanımlaması yapılmıştır.

String name = "Muhammet";

    Yukarıdaki tanımlama String Literals olarak adlandırılmaktadır. String literals, bir programcının belirli bir değeri ifade etmek amacıyla yazdığı sabit karakter dizileridir.

    Yukarıda String türünde tanımlanan ve name olarak adlandırılan nesne elbette primitive tiplerden(int,byte,long vb.) farklı olarak Stack yerine Heap bölgesinde tutulmaktadır, dolayısıyla bir referansa sahiptir. Yani derleyici bu satırı çalıştırdığında Heap bölgesinde “Muhammet” değerini tutan bir obje oluşturur ve “name” isimli değişkene bunun referansını verir.

    Peki devam eden kısımda aşağıdaki gibi aynı değere sahip ikinci bir değişken tanımlaması yapsaydık bu iki nesnenin referansı aynı mı olurdu? Bunu anlamak için referanslarının hashCode değerlerini ekrana yazdıralım.

String name = "Muhammet";
String name2 = "Muhammet";

System.out.println(System.identityHashCode(name));
System.out.println(System.identityHashCode(name2));

//Output
//1705736037
//1705736037

    Evet! Görüldüğü üzere her iki nesnenin de referanslarının hashCode değerlerini ekrana yazdırdığımızda aynı değeri yazdığını görüyoruz. Yukarıdaki örnekte iki tane değil bir milyon tane değişken de tanımlasaydık bunların tamamının referansı aynı olacaktı.

    Buradan anlıyoruz ki biz bir milyon tane değişken tanımlasak da JVM bunlara karşılık Heap bölgesinde yalnızca bir tane obje tanımlıyor.

Peki Neden?

    Tabii ki amaç bellek optimizasyonu. Varsayılan olarak literals kullanarak bir String objesi oluşturduğunuzda JVM oluşturmak istediğiniz değerin varlığını String Pool yapısı içerisinde kontrol eder. Eğer burada zaten bu değer mevcut ise, yeni bir tane oluşturmak yerine geriye bu objenin referansını döner. Bu sayede tekrar eden verinin önüne geçilir.

Nedir bu String Pool?

    Makalemizin başlangıcındaki görselden görüldüğü üzere JVM Heap bellek kısmı içerisinde String Pool adı verilen bir alan vardır. Bu alan aynı zamanda String Constant Pool veya String Intern Pool olarak da adlandırılır.

    Siz bir String oluşturduğunuzda JVM varsayılan olarak önce bu alanı kontrol eder. Eğer bu alanda, oluşturduğunuz String değişken içerisindeki değer zaten daha önce tanımlanmış ise onun referansı değişkeninize atanır. Eğer öncesinde böyle bir değer String Pool içerisinde tanımlanmamış ise String Pool içerisinde bu değer tanımlanır ve değişkeninize atanır.

    Bundan sonra oluşturacağınız tüm String değişkenlerin değerleri bu alandan gelir veya bu alan içerisine tanımlanırlar. Bu sayede tekrar eden verinin önüne geçilmiş olur ve bellek kullanımı önemli ölçüde azaltılmış olur.

Peki String Pool Dışında String Tanımlamak İstersek?

    String Pool içerisinde işleri yürütmenin getirdiği bellek kullanımında tasarruf avantajının yanısıra her yeni String değişken oluşturduğunuzda bu alanın baştan sonra kontrol edilmesi gibi bir search işlemi gerçekleşir. Kimi zaman bellekten tasarruf etmek yerine buradaki işlem’in gecikmesinden, yükünden kaçınmak isteyebiliriz.

    Böyle durumlarda String Pool dışında, doğrudan Heap içerisinde String değişkenlerimizi tanımlamak, yönetmek isteyebiliriz. Bunun için tek yapmamız gereken tanımlama yaparken new anahtar kelimesini kullanmak.

String name = "Muhammet";
String name2 = "Muhammet";
String name3 = new String("Muhammet");

System.out.println(System.identityHashCode(name));
System.out.println(System.identityHashCode(name2));
System.out.println(System.identityHashCode(name3));

//Output
//1705736037
//1705736037
//455659002

    Yukarıdaki örnekte görüldüğü üzere new anahtar kelimesi kullanılarak String değişken tanımlandığında, farklı bir referansa sahip String Pool dışında tanımlamış oluyoruz.

String name = "Muhammet";
String name2 = "Muhammet";
String name3 = new String("Muhammet");

System.out.println(name == name2);
System.out.println(name == name3);
System.out.println(name.equals(name3));

//Output
//true
//false
//true

    Bu değişkenleri “==” operatörü kullanarak karşılaştırdığımızda, String Pool dışında olan ile içinde olan iki farklı değişken için sonuç false dönerken, String Pool içerisinde olan iki farklı değişken için sonuç true dönüyor.

    Bunun sebebi == operatörü kullanarak yapılan karşılaştırmalar değerler üzerinden değil referanslar üzerinden yapılır. Dolayısıyla String Pool içerisindeki aynı değere sahip değişkenlerin referansı aynı iken, new anahtar kelimesi ile tanımlanan değişkenin referansı farklı.

    Fakat referansları üzerinden değil değerleri üzerinden karşılaştırmak istersek de equals metodunu kullabiliriz.

intern() Fonksiyonu

String name4 = new String("Java");
String name5 = name4;

System.out.println(System.identityHashCode(name4));
System.out.println(System.identityHashCode(name5));

//Output
//250421012
//250421012

    Yine kodlar üzerinden ilerleyelim. Yukarıdaki örnekte name5 isimli değişkeni name4 değişkeninden türetiyoruz. Dolayısıyla referansları aynı. Fakat String Pool içerisine alınmıyorlar. Çünkü Heap üzerinde yaratıldı, Heap üzerinden referans alındı.

    Fakat bunun yerine oluşturacağımız yeni nesneyi String Pool içerisine koymak istiyor olabiliriz. Bu durumda .intern() fonksiyonu devreye giriyor.

String name4 = new String("Java");
String name5 = name4;
String name6 = name4.intern();
String name7 = "Java";

System.out.println(System.identityHashCode(name4));
System.out.println(System.identityHashCode(name5));
System.out.println(System.identityHashCode(name6));
System.out.println(System.identityHashCode(name7));

//Output
//250421012
//250421012
//1915318863
//1915318863

    Yukarıda “name6” isimli değişkeni oluştururken name4 değişkenini kullandık. Bu değişken String Pool’da değil, Heap üzerinde kendi başına bulunuyordu. Fakat bundan bir değişken oluştururken .intern() metodunu kullanarak oluşturduk. Bu metod sayesinde eğer String Pool’da böyle bir değer yoksa oluştur ve String Pool’a ekle demiş olduk.

    Devamında “Java” değerine sahip bir String değişkeni String literals kullanarak tanımladığımızda referansının String Pool’dan geldiğini görebiliyoruz.

Gelelim String Pool kavramının artı ve eksilerine;

Artılar

  • Performans. JVM yeni bir String objesi yaratmak yerine varolan üzerinden referans aldığı için String işlemleri daha hızlıdır.

  • Bellek Kullanımı. String Pool içerisinde bulunan tek bir String’i referansı üzerinden sürekli paylaştığınız için sürekli yeni String objeleri oluşturmaz ve bellek kullanımını önemli ölçüde azaltabilirsiniz.


Eksiler

  • Performans. Evet artılarda olan madde burada da var. Bunun sebebi yeni bir String değişken oluşturduğunuzda bellekte direkt olarak yenisini oluşturmak yerine, String Pool içerisinde arama işlemi yaptırmak zorunda kalırsınız. Böyle bir değer varsa yenisini oluşturmayalım derken eğer yüksek sayıda String objeleri ile çalışıyorsanız JVM kimi zaman koskoca bir havuzu taramak zorunda kalabilir. Ve bunu her seferinde yapacağı için eğer yüksek sayıda String objesi ile çalışıyorsanız String Pool yapısı size faydadan çok zarar getirebilir, dikkatli olmak zorundasınız.


1 yorum

Derslerim dedi ki...

Tesekkurler

Rastgele İçerik

DonanımHaber

© tüm hakları saklıdır
made with by templateszoo