Ana içeriğe atla

V for Java - Project Valhalla - 1. Kısım

Project Valhalla OpenJDK tarafından yürütülmekte olan bir proje. Java'nın tip sistemi ile ilgili Java programlama dili ve JVM üzerinde yapılabilecek geliştirmelerin araştırıldığı ve adım adım sona yaklaşan bu proje bir takım ilginç yenilikler sunuyor. Bunları:

  • Value objects / value classes (Değer nesneleri, değer sınıfları)
  • Primitive objects / primitive classes (Primitif nesneler, primitif sınıflar)
  • Primitif ve nesne tiplerinin birleştirilmesi


olarak sıralayabiliriz. Tip sistemleri ile ilgili daha teorik bilgi için ilgili yazımıza göz atabilirsiniz.

Güzel de, "value" nedir, "object" nedir biliyoruz ama "value object" neyin nesidir ? Gelin beraber bir göz atalım.

 


 

Primitifler, Sınıflar ve Kimlik (Identity)

Java Tip Sistemi; 8 pritimif (byte, short, int, long, float, double, char ve boolean), nesne (object) ve dizi (array) olmak üzere 10 tanımlı tipten oluşur. Primitif tipler ile ifade edilemeyen daha karmaşık veri yapıları  (örneğin bir string yani karakter katarı, uzayda 3 koordinatı olan bir nokta) pritimif tipleri bir araya getiren sınıflar (class) ve bunların nesneleri ile modellenebilir. Sınıflara kullanıcı (geliştirici) tanımlı tipler olarak bakılabilir. Primitif tipler ve kullanıcı tanımlı tipler (ve bunların dizileri) ile ihtiyaç duyulabilecek tüm veri yapıları oluşturulup kullanılabilir. Primitifler ve sınıflar (ve onların nesneleri) bir arada çok kullanışlı bir tip sistemi sunsa da ikisi arasındaki temel bir farkı bu yazı açısından vurgulamamız gerekiyor: kimlik ve eşitlik.

Nesnelerin bir "kimliği" olduğundan söz edilebilir. Aynı sınıfın iki nesnesi, tamamen aynı değerleri içerse de, bellekte iki farklı yerde, birbirinden farklı iki nesnedirler; yani bir anlamda kendi kimlikleri vardır. Aynı şeyi primitif tipler için söylemek pek mümkün değil. Yani bir int değişkeninin değeri "5" ise, "hangi 5? oradaki 5 mi? buradaki 5 mi?" diye sormanın bir mantığı yoktur çünkü "5, 5'tir". Şöyle bir metafor daha deneyelim: İki kırmızı duvar; boyutları, malzemeleri ve renk tonları tamamen aynı olsa da, sonuçta 2 farklı duvardır. Ama bunu renkleri için söyleyemeyiz, aynı tonda kırmızı olduktan sonra "hangi kırmızı ? 1. duvardaki kırmızı mı ? 2. duvardaki kırmızı mı?" diye sormak mantıklı değildir. Bu metafordaki duvarlar, nesneler; renk ve boyut ise primitifler gibi düşünülebilir.

Java'da nesne kimlik karşılaştırması "==" operatörü ile yapılır, eşitlik kontrolü ise equals() metodu ile. İki nesne "equal" (eşit) olsa da, aynı değildir. İşte bu farklılık, bu kimlik konusu; JVM seviyesinde primitif tipler ile nesnelerin bellekte farklı şekilde ve bölgelerde tutulmalarına ve farklı şekilde ele alınmalarına neden olur.


Nesne Başlığı  (Java'da niye sizeof yok?)

Valhalla tarafından ortaya konan Value Object / Class ve Primitive Object / Class kavramlarının bize ne kazandırdığını anlayabilmek için nesnelerin JVM tarafından bellekte nasıl tutulduğuna göz atmamız gerekiyor.

JVM bir sınıfın nesnesi için bellekte yer ayırdığında, sınıf içindeki alanlar için gereken yere ek olarak, nesne başlığı (object header) denen bir veri yapısı için de yer ayırır. Bu nesne başlığı JVM tarafından bir takım mekanizmalar için ve Java'yı nesneye yönelik (Object Oriented - OO) bir dil yapan polymorfizmi sağlamak ve yabancısı olana sihir gibi görününen reflection (yansıma) özelliğini gerçeklemek için kullanılmaktadır.

Gelin şu nesne başlığı içindeki veriyi biraz daha detaylı inceleyelim. Nesne başlığının ilk kısmı Mark (işaretleme) Word olarak adlandırılır. JVM bu Mark Word kısmını şu amaçlarla kullanır:

  • Senkronizasyon / Locking (kilitleme): Java'nın reklamı yapılırken kullanılan "en baştan multi threading için tasarlandı" benzeri iddiaların dayanağı olarak hangi thread'in bu nesneye erişim hakkını rezerve ettiğini yani kilitlediğini depolamak
  • Garbage Collection: Java'nın en cazip özelliklerinden biri olan otomatik bellek yönetimini sağlayan Garbage Collector (çöp toplayıcı) tarafından nesnenin kullanılıp kullanılmadığını (ve ilgili detayları) depolamak (bir nevi işaretlemek)
  • Nesne Kimliği / Hash: Nesneyi tekil olarak temsil eden hash code (özet kodu diye çevirmeyi deneyelim) yani nesne kimliği bilgisini depolamak

Mark Word'den hemen sonra gelen Class Pointer (Sınıf İşaretçisi) ise nesnenin oluşturulduğu sınıfın bellekteki temsiline işaretçi bilgisidir. "Sınıfın bellekteki temsili" derken; geliştiricinin senktaks seviyesinde yazdığı sınıfı, çalışma zamanında (runtime) sorgulanabilir olarak tutan bir veri yapısından bahsediyoruz. Çalışma zamanında bu veri yapısı kullanılarak; "bu sınıf hangi sınıftan miras almış (extend etmiş) ?", "bu sınıfta hangi metotlar var?", "bu metotların argüman ve dönüş tipleri nelerdir?" gibi birçok kritik soruya dinamik olarak cevap alınır. İşte bu; yani çalışma zamanında bir nesnenin sınıfına, sınıfından da o nesnenin detaylarına dinamik olarak erişebilmek Java platformunun 2 temel özelliğine can verir:

  1. Inheritance (miras) / polymorphism (çok biçimlilik): Nesneye yönelik programlamanın temellerinden olan; bir nesnenin başka bir nesnenin özelliklerini miras alabilmesi ve aldığı bu özellikleri değiştirebilmesi
  2. Reflection (yansıma): Daha teorik adıyla Çalışma Zamanı Tip Bilgisi (RTTI - Run-time Type Information) başlı başına bir yazı konusu olmakla birlikte; Hibernate, Lombok vb birçok "sihir" gibi görünen kütüphaneyi mümkün kılan nesne ile ilgili dinamik bilgi erişimi

 


Nesne başlığının Java'nın popülerliğini sağlayan temel özellikleri için ne kadar hayati olduğu açık ama işte hayat, her şeyin iki yönü var. Java nesnelerinin boyutu içerdikleri alanların (field) toplamından daha fazla ve örneğin C/C++ dillerindeki "sizeof" gibi nesnenin bellekte ne kadar yer kapladığını söyleyen bir operatör yok. Java'nın bellek açısından verimsiz olduğu yönündeki eleştirilerin (kulaktan dolma olmayanlardan bahsediyoruz) merkezinde işte bu nesne başlığı yer alır. Nesne başlığı, oluşturulan her bir nesne için; 64 bit sistemlerde minimum 16 byte ve 32 bit sistemlerde minimum 8 byte yer kaplar. Bunları minimum olarak belirttiğimize dikkat edin çünkü JVM gerçeklemeleri nesne başlığının nasıl ve nerede tutulacağı konusunda tamamen özgür, yeterki yukarıda bahsedilen özellikleri sağlasınlar. Ve geliştiriciler olarak JVM'in tamamen kendi için tuttuğu bu başlığa müdahale etmemiz mümkün değil-di. Ta ki "Project Valhalla'ya" kadar.


Value Object ve Value Class

Nesne başlığının sunduğu imkanlar açık ancak yazılan sınıfların tümünün bahsedilen imkanlara ihtiyaç duyduğunu söylemek zor. Birçok nesne senkronizasyon amacıyla lock (kilit) olarak kullanılmıyor ve çoğu için de nesnenin bellekteki yeri (yani kimliği) değil de eşitliği (yani alanlarının değerlerinin eşitliği) asıl ilgilendiğimiz şey oluyor. Sadece değer tutmak ve bu değerler üzerinde işlem yapmak için yazılan sınıfların tüm sınıflar içinde oldukça büyük bir orana sahip olduğunu söylemek mümkün. İşte Valhalla bu tür sınıflar için bize yeni bir sınıf türü sunuyor: Value Class. Yeni bir keyword’ümüz var, hemen inceleyelim:


// tanımlama
value class Counter {

    private int counter;

    public Counter(int value) {
    	checkSubzero(value);
        this.counter = value;
    }

    public int get() { return counter; }

    public Counter increment(int delta) {
        return new Counter(this.counter + delta);
    }
    
    private static void checkSubzero(int value) {
        if (value < 0) {
            throw new IllegalArgumentException();
        }
    }

}

// kullanım
Counter counter = new Counter(0);
counter = counter.increment(1);
System.out.println(counter.get());

// eşitlik ve kimlik
assert counter == new Counter(1);

 
Görüldüğü üzere bir değer sınıfı ve bundan üretilen bir değer nesnesi büyük oranda normal bir sınıf gibi tanımlanıyor ve kullanılıyor. Fakat değer sınıfları bir takım kısıtlamalara sahip:
  • Kimlik ve Eşitlik: Değer nesneleri kimliksiz nesneler, "==" operatörünün kimlik kontrolü yaptığı hatırlanırsa bu operatör değer nesneleri için "equals()" metodu gibi çalışmalı, iki değer nesnesi (daha doğrusu referansları) "==" ile karşılaştırıldığında alanlarının değerlerinin esit olup olmadığı kontrol edilir, alanları eşit ama birbirinden farklı iki değer nesnesi olamaz
  • Immutability (Değişmezlik): Değer sınıfının kendisi ve tüm alanları varsayılan olarak final, yani değer sınıfları extend edilemezler ve abstract olamazlar, buna ek olarak alanlarına bir kez değer atandıktan sonra bir daha değer atanamaz
  • Miras alamama (No inhertitance): Bir değer sınıfı ya direkt Object sınıfını extend edebilir veya alanları olmayan (dolayısı ile state sahibi olmayan) soyut (abstract) bir sınıfı extend edebilir, interface konusunda bir kısıt yok
  • Senkronizasyonsuzluk: Açıklaması yazmasından daha kolay, değer sınıflarındaki nesne metotları "synchronized" olamaz ve bir değer nesnesi synchronized blok için kilit olarak kullanılamaz

Bu kısıtların neden kaynaklandığını (bazı okuyucularımız için barizdir belki) açıklayıp 1. kısmı az sonra sonlandıracağız ancak ondan önce belirtmekte fayda var: bu kısıtlar dışında değer sınıf ve nesneleri constructor overloading, iç sınıflar, static alanlar, birden fazla interface'den türeme gibi alışılmış sınıf ve nesnelerle aynı özelliklere sahip olabilirler. 

 

Peki ne kazanıyoruz ?

Değer sınıfları ve nesnelerinin yukarıda sayılan kısıtlamalara sahip olması onları bir konuda avantajlı kılıyor, evet tahmin ettiniz: nesne başlığı! Miras ve polymorfizm kısıtlaması ile nesne başlığı içindeki Class Pointer ihtiyacı ortadan kalkıyor ve senkronizasyon için kullanılamamaları da Mark Word ihtiyacını azaltıyor. 

Nesne başlığına ek olarak; eşit 2 değer nesnesi arasında kimlik açısından bir fark olmadığı için bunlar bellekte serbestçe kopyalanabilir, alanlarına parçalanıp tekrar bir nesne olarak birleştirilebilir ve program açısından bu hiçbirşey farkettirmez. Bu da JVM'e; değer nesnelerinin bellekte nerede ve ne kadar ek başlıkla tutulabileceği konusunda optimizasyon imkanları sunuyor. Optimizasyon derken: daha az bellek tüketimi ve modern işlemci mimarilerinde daha yüksek performanstan bahsediyoruz. Modern işlemci mimarilerinden bu serinin sonraki kısmında bahsedeceğiz.


Hepsi bu kadar değil

Nesne başlığının olmaması (veya daha küçük boyutta olabilmesi) bellek tüketimi üzerinde olumlu bir etkiye sahip olmakla birlikte Project Valhalla'nın kapısını araladıkları bunla sınırlı değil. Giriş kısmında da belirttiğimiz Primitif Sınıf ve Primitif Nesne konularını 2. yazımızda tartışacağız. Neticede çok uzun yazıları kimse okumaz değil mi ? 

Görüşmek üzere.

Yazının 2. kısmına buradan ulaşabilirsiniz.

 

Yorumlar

Bu blogdaki popüler yayınlar

Tip Sistemleri ve Programlama Dilleri

Tip Sistemi kavramı, günlük hayatlarının bir parçası olmasına rağmen bir çok yazılım profesyoneli için bile kulağa yabancı gelebilir. Tip Sistemleri; matematik ve mantık dallarındaki zengin bir konu olan "Tip Teorisinin" yazılım geliştirme ve programlama dillerine bir yansımasıdır. Tip sistemlerinin programlama dilleri için oldukça önemli ve belirleyici olduğunu söyleyebiliriz.  Bu yazıda herhangi bir programlama diline odaklanmadan teorik düzeyde tip sistemlerinden bahsetmekle yetineceğiz. Tip sistemleri; bir programlama dilindeki değişken, fonksiyon vb yapı taşlarınının kullanım ve birbirleri ile etkileşimlerini, belli kurallara bağlayarak, oluşabilecek belirsizlikleri ve hataları engellemeye yönelik mantıksal sistemlerdir. Havalı cümlemizi kurduğumuza göre daha anlaşılır olarak açıklamak gerekirse örneğin bir değişkenin hangi türde değerleri tutabileceği bir fonksiyonun hangi türde parametrelerle çağrılması gerektiği yine bir fonksiyonun bir değer üretip üretmediği ve üre...

Uzaktan / Bulut İmza (Remote / Cloud Signature)

İmza, kişinin; o belgede yazanı onayladığını ve ona uyacağını gösteren işarettir. Bilgisayarlar hayatımıza girdiğinden beri belgeler bilgisayarlarda üretilir oldular ama sonuçta yazıcılardan çıkıp fiziksel olarak önümüze geldiler ve kalem mürekkep ile ıslak olarak imzalandılar. Günümüzde kurumlar ve devlet birimleri dijital dönüşüm ile gittikçe daha kağıtsız bir yapıya kavuşuyor. Belgeler bilgisayarlarda üretiliyor, hiç kağıda yazılmıyor ve tamamen elektronik ortamda kalıyorlar.  Bulut imza, Signature as a Service (Bulut Bilişim ile ilgili yazımıza buradan ulaşabilirsiniz) şeklinde kullanılmak üzere ve dijital dönüşüm yapbozundaki yasal/hukuki eksiği tamamlamak için geliyor. Bu büyük yeniliği anlamak için gelin şu anda elektronik ortamda imza nasıl atılıyor ve hangi zorlukları içeriyor bakalım. Sonra bulut imzayı tanıyalım ve ülkemizde teknik ve yasal mevzuat bakımından ne durumda olduğu ile yazımızı sonlandıralım. Elektronik ve Dijital İmza Elektronik imza; elektronik ort...

AWS, GCP, Azure... Yok mu bu bulutun bir kolayı ?

AWS - Amazon Web Services, GCP - Google Cloud Platform, Microsoft Azure... 3 büyük bulut sağlayıcı. Bulut bilişim konusu biliyorsunuz çok revaçta. Geliştiricilier, proje yöneticileri ve hatta siyasetçiler bile buluttan bahsediyor. İlk başta göze korkutucu geliyor. Bulut bilişim ile ilişkili ve bir manada o sayede mümkün bir çok yeni kavram var. Bahsettiğimiz 3 büyük sağlayıcının her biri yüzlerce farklı servis sunuyor. Tüm detayları konuşmak mümkün değil elbet ama yok mu bu konuya giriş yapmanın, detaylı olarak incelemeden önce ana hatlarıyla konuyu akılda oturtmanın bir yolu ? Bu yazımızda bunu deneyeceğiz.   Nedir bu Bulut Bilişim ? Gelin önce şu "servis" kelimesinden bahsedelim. Çok geniş anlamda kullanılıyor ancak şu yaygın tanımı tam da konumuza göre: "Taşıma, iletişim, elektrik, gaz vb gibi temel ortak ihtiyaçları herkese açık olarak veren sistemler". Elektrik ve gaz kısmını boşverirsek (hele 1 ocak sonrası) bu tanım şu önemli 2 özelliği öne çıkarıyor: O siste...