Java’da Bellek Yönetimi

Oğuzhan Çevik
Pera Soft
Published in
6 min readJul 16, 2019

Hepimiz hemen her gün onlarca, hatta yüzlerce satır kod yazıyoruz ama çoğu kez işin arka tarafında mutfakta bu işlerin nasıl yürütüldüğünü merak ederiz. Bende bu yazıda Java Memory Management kursundan aldığım notları sizlerle paylaşacağım.

Java’da yeni bir nesne oluşturmak için new anahtar kelimesini kullanırız. Oluşturduğumuz nesneler hafızada tiplerine göre Stack’te veya Heap’te tutulur.

Value type (değer tipli) nesnener Stack’te tutulur. Java’da Primitive tipler dediğimiz byte, char, int, long, double, boolean… gibi tiplere karşılık gelmektedir.

Reference type (referans tipli) nesnelerin değerleri Heap’te referansları ise Stack’te tutulur. Java’da Wrapper tipler dediğimiz Integer, Long, Double, Boolean, Object, Person (kendi özel tipimiz) tiplerine karşılık gelmektedir.

STACK ve HEAP Kavramı

Kısaca Stack

  • LIFO (Last in First out) son giren ilk çıkar mantığında çalışır.
  • Veri depolama alanı çok geniş olmadığından kullanımı kolay ve hızlıdır.
  • Veriler Big and Little Endian (artan ya da azalan) adres mantığında tutulur.
  • Derleme zamanında oluşturulur.
  • Life time (yaşam süresi) kısa olan değişkenler tutulur. Ör; local variables (yerel değişkenler).
  • Static allocation (Kullanılacak depolama alanının boyutu biliniyorsa stack işe yarayacaktır.)
  • Bir Java uygulamasında sadece tek bir stack yoktur. Her bir thread’in kendi stack’i vardır.
  • Bir stack üzerindeki veriye kendi thread’inden başka bir thread erişemez.
  • Doğru kullanılmadığında java.lang.StackOverFlowError hatası alınır.

Kısaca Heap

  • Heap stack’e göre daha büyük boyuta sahiptir.
  • Stack’e göre daha fazla alana sahip olduğundan stack’e göre daha yavaştır.
  • Heap’teki veriler karışık şekilde sıralanır.
  • Çalışma zamanında oluşturulur.
  • Dynamic allocation (Kullanılacak depolama alanının boyutu bilinmiyorsa ya da sürekli değişken olacak ise heap kullanmak doğru olacaktır.)
  • Bir Java uygulamasında tüm thread’ler için sadece bir tane heap bulunmaktadır.
  • Doğru kullanılmadığında java.lang.OutOfMemoryError hatası alınır.
Serkan Sakınmaz Java — Stack ve Heap Kavramı

Autoboxing and Unboxing

Java 5 ile gelen bu özellik sayesinde java compiler primitive tip ile wrapper tip arasındaki dönüşümü yapabilmektedir.

Autoboxing and Unboxing

Autobaxing primitive tiplere karşılık gelen referans tipler arasındaki dönüşümdür.
Örneğin : int → Integer , double → Double

Unboxing Yukarıdaki işlemin tersi yönünde bir dönüşüm işlemine denir.
Örneğin : Integer → int , Double → double

List<Long> numberList = new ArrayList<Long>();long number = 65;numberList.add(number); // autoboxinglong firstElement= numberList.get(0); // unboxing

Java’da Parametre Geçirme

pass by value

Metoda gönderilen parametrenin bir kopyasının tutularak gönderildiği parametre aktarım şeklidir. Yani metot içinde parametrenin değeri değiştiğinde ilk değeri değişmez. Değişiklik sadece metot scope içinde görülür.

pass by reference

Metoda gönderilen parametrenin referansının gönderildiği parametre aktarım şeklidir. Metot içinde parametrenin değeri değiştiğinde ilk değeride değişir.

https://twitter.com/turkishdevelop/status/1138886862129549313

Java pass-by value yaklaşımını kullanmaktadır.

Görüldüğü gibi number ve person nesnesinin değeri metot içerisinde değiştirildi.

Metot dışına çıkıldığında main metodu içerisinde yazdırıldığında ilk değerlerini koruduğu görülüyor.

Bu nedenle Java kesinlikle pass-by-value yaklaşımını kullanmaktadır.

Final kullanımı

Final anahtar kelimesi programın daha doğru, hatalara dayanıklı ve performanslı çalışmasını sağlar.

Final anahtar kelimesi sınıf değişkenleri, metot parametreleri, metotlar ve sınıflar için kullanılmaktadır.

Sınıf değişkenleri: Değişkenler için final anahtar kelimesi kullanmak demek değeri sonradan değiştirilemeyen değişkenler oluşturmak demektir. Sadece bir kere değer ataması yapılabilir ve bu atama tanımlandığı yerde veya sınıfın constructor’ında (yapılandırıcısında) gerçekleşebilir.

Metot parametresi: Metot’lara geçilen parametre final olarak tanımlanırsa metot içerisinde o parametrenin değeri değiştirilemez. Metot parametrelerinin tamamen final olarak tanımlamış olmalarında büyük fayda vardır. Bu şekilde parametrenin metot bünyesinde değişikliğe uğrama tehlikesi kaldırılmış olur.

Metot: Final olarak tanımlanan bir metot alt sınıflar tarafından override edilemez.

Sınıf: Final olan bir sınıf extend edilemez (genişletilerek bir alt sınıf oluşturulamaz).

Static kullanımı

Static anahtar kelimesi Java’da değişken’ler, blok’lar, metot’lar ve inner-class’lar için kullanılabilir. Static tanımlanan bir değişken veya metot nesnelerden bağımsız olarak var olurlar. Yani static anahtar kelimesi, nesnelere değil sınıflara aittir. Static değişken veya metot, nesne oluşturmadan sınıf ismi ile erişilebilir. Static ifadeler nesneler tarafından paylaşılırlar.

Java static keyword

Static olmayan değişkenler nesnenin oluşması ile birlikte oluşur ve bellekte nesneye ait alanda yer alırlar. Static değişkenler ise sınıfın oluşturulması ile birlikte bellekte yerlerini alırlar. Böylece her nesne oluşmasında tekrar tekrar bellekte bu değişkenin yer tutması için belleğe başvurulmaz. Çünkü static değişkenin yeri sınıf oluşturulurken açılmıştır.

Static anahtar kelimesi blok’lar içinde kullanılır. Java’da static initialization block ve instance initialization block vardır. Bir sınıf yüklendiğinde ilk olarak ve sadece bir kez static initialization blok çalışır. Yeni bir instance oluşturulduğunda her defasinda instance initialization block çalışır.

Java’da Static Initialization Block kullanımı

Sınıf seviyesinde static kullanımı sadece inner-class’lar için kullanılabilir. Stataic-inner-class’tan bir instance oluşturmak için outer-class’ın referansına ihtiyaç yoktur. Stataic-inner-class, outer-class’ın sadece static üyelerine erişebilir. Non-static bir üyeye erişmek istediğinde derleme hatası alır.

Java’da Static Inner Class kullanımı

Garbage Collector

Garbace Collector Java’nın en büyük nimetlerinden birisidir. Orta seviyeli dillerde bir nesneye artık ihtiyacınız olmadığında onu bellekten silmek zahmetli bir iştir. Bu dillerin en büyük sorunlarından birisi dinamik bellek yönetimidir. Java geliştiricileri bu konuda oldukça rahattır. Çünkü JVM tarafından GC ile referansı olmayan nesneler tespit edilip hafızadan silinir. GC’nin amacı hafızada bulunan ve ulaşılamayan (referansı olmayan) nesneleri hafızadan silmek ve hafızada yeni nesneler için boş alan açmaktır.

https://twitter.com/System32comicsA/status/1308134334595911681

GC’nin çalışması için istekte bulunma

GC, JVM’nin kontrolü altındadır. GC’nin çalışması için JVM’e istekte bulunuruz. Fakat isteğimizin kabul edilip edilmeyeceğinin bir garantisi yoktur. İstekte bulunmak için System.gc() veya Runtime.getRuntime().gc() fonksiyonlarını çağırırız. GC çalıştığında finalize() methodu tetiklenir. Burada yapılacak son işlemler var ise bu metot içinde yapılır.

GC çalışması için istekte bulunma finalize metodunun çalışması

Şimdi GC çalıma mantığına bakalım.

Garbage Collector nasıl çalışır?
  • Uygulama çalıştığında heap boş olur.
  • Dolduğunu varsayalım ve GC gelip kullanılmayan nesneleri temizler. Bu ilk temizlemede, sağ kalan nesneler Generation #0 olarak tanımlanır.
  • Tekrardan dolduğu ve GC’nin çalıştığını varsayalım. Generation #0'dan sağ kalanlar Generation #1 olarak tanımlanır ve yenilerden sağ kalanlarda Generation #0 olarak tanımlanır.
  • Tekrardan dolduğu ve GC’nin çalıştığını varsayalım. Generation #1'den sağ kalanlar Generation #2 olarak tanımlanır ve Generation #0'dan sağ kalanlar Generation #1 olarak tanımlanır. En yenilerden sağ kalanları Generation #0 olarak tanımlanır.

Tuning JVM (JVM’yi ayarlama)

Java geliştiricileri java.lang.OutOfMemoryError hatasıyla karşılaşmak istemezler. Eğer bellek yönetimi doğru yapılamaz ise bu hatayla karşılaşmak muhtemeldir.

Ör; uygulamanın ayağa kalkaması için minimum bellek boyutu doğru ayarlanmamış ise bu hata ile karşılaşılır.

# Xms heap alanının başlangıç miktarını belirtir
# Xmx heap alanının maximum miktarını belirtir
JVM argümanlarının tüm listesine
buradan ulaşabilirsiniz.

Xms512m -Xmx1024m

JVM başlangıçta bellek miktarını 512 MB olarak ayarlayacaktır. Bu rakamı aşan bir ihtiyaç olduğunda ise 1024 MB’a yükseltecektir.

--

--

Pera Soft
Pera Soft

Published in Pera Soft

Pera olarak, iş dünyasının karmaşıklığını anlıyor ve teknolojinin hızlı değişimine liderlik ediyoruz!