---
title: 'Bellek Alanları'
source: 'https://academia.sh/tr/kurslar/jvm-ve-eszamanlilik/bellek-alanlari'
course: 'JVM, Eşzamanlılık ve Başarım'
language: tr
updated: '2026-08-23T07:00:57+00:00'
license: 'CC BY-SA 4.0'
---

# Bellek Alanları

Aynı iş parçacığının yazdığı altı değerden üçü başka bir iş parçacığına hiç görünmez, üçü görünür — ayrımı belirleyen değerin türü değil durduğu yerdir: yerel değişken ve parametre çağrı çerçevesinde, nesne alanı ve dizi ögesi öbekte, statik alan sınıfa ait alanda durur. Paylaşılan olmak görülecek olmak değildir: bir sıralama aracı olmadan aynı okuma tanımsızdır.

Önceki derste sınıfın çalışma zamanına kimin elinde girdiği ölçüldü: hangi yükleyicinin
tanımladığı, hangi iş parçacığının başlattığı. Ama başlatılan sınıfın alanları nerede
durduğu, ve bir iş parçacığının yazdığı değeri başka bir iş parçacığının görüp göremediği
hiç sorulmadı. Bu ders o soruyu sorar: bir değeri kaç iş parçacığı görebiliyor?

Yanıt değerin türüne bakılarak verilemez — `int` de olsa aynı `int`, bir yerde yazan iş
parçacığının dışına hiç çıkmaz, başka bir yerde her iş parçacığına açık durur. Ayrımı yapan
şey değerin **durduğu yer**dir.

Bu ayrımın önemi, iki iş parçacığının aynı yöntemi aynı anda çağırdığı sıradan bir durumda
görülür. İki iş parçacığı `parametreYaz(5, ...)` yöntemini tam olarak aynı anda çağırsa
bile, ikisi de kendi `p` parametresini kendi çerçevesinde tutar; biri ötekinin `p`'sini
hiçbir şekilde okuyamaz, çünkü ikisinin çerçevesi ayrı adres uzayında değil ama ayrı
**çerçeve zincirinde** durur. Bu, programcının bir şey yapmasıyla kurulan bir izolasyon
değildir — dilin kendisi tarafından, hiçbir kilide ve hiçbir anahtar sözcüğe gerek
kalmadan sağlanır. Öbek paylaşımı ise tam tersi yönde çalışır: bir nesnenin öbekte
paylaşılması, o nesnenin referansının başka bir iş parçacığına **verilmiş olmasına**
bağlıdır; referans hiç paylaşılmazsa öbekteki bir nesne de yalnız tek bir iş parçacığına
görünür kalabilir. Çağrı çerçevesi izolasyonu yapısaldır, öbek paylaşımı ise bir tasarım
kararıdır.

## Dört Yer: Çağrı Çerçevesi, Öbek ve Sınıfa Ait Alan

Bu konunun kataloğundaki alt başlık bellek alanlarını "yığın, yığıt ve meta alan" diye anar.
Bu platformda **yığın** bir veri yapısının (öncelik ağacının) adıdır ve bellek alanı için
kullanılmaz; düzyazı burada ve bundan sonra hep **öbek** yazar. Üç alanın üçü de JVM
belirtiminin kendi çalışma zamanı veri alanları arasında adı geçen alanlardır: her iş
parçacığının kendi yığıtı, bütün iş parçacıklarının paylaştığı tek bir öbek, ve yine bütün
iş parçacıkları arasında paylaşılan tek bir yöntem alanı. Belirtim bu üç alanın nasıl
gerçekleştirileceğini söylemez — yalnız hangi verinin hangi alana ait olduğunu söyler; bu
ders de yalnız o ayrıma bakar, gerçekleştirime bakmaz.

Çalışma zamanı bir değeri üç ayrı alandan birine koyar. Bir yöntem çağrıldığında, o iş
parçacığının kendi **çağrı çerçevesi** açılır ve yöntemin yerel değişkenleri ile
parametreleri oraya yazılır; her iş parçacığının kendi çerçeve zinciri vardır, biri
ötekininkine erişemez. Çerçeve, çağrı bittiğinde de kapanır: bir yöntem özyinelemeli
çağrılırsa aynı iş parçacığında aynı yöntemin birden çok çerçevesi üst üste durur, ama
hiçbiri bir başka iş parçacığının çerçeve zincirine karışmaz. Bir nesne `new` ile
üretildiğinde alanları ve bir dizi üretildiğinde ögeleri **öbeğe** yazılır; öbek bütün iş
parçacıklarının paylaştığı tek bir alandır ve bir nesneye giden referans hangi iş
parçacığına aktarılırsa o iş parçacığı da aynı alanlara ulaşır. Bir sınıfın kendi statik
alanları ise örneklerden ayrı, sınıfın kendisine ait bir alanda durur — JVM belirtiminin
**yöntem alanı**, güncel adıyla **meta alan**; bu alan da bütün iş parçacıkları arasında
tektir ve paylaşılır. Statik bir alanın var olması için sınıftan tek bir örnek bile
üretilmiş olması gerekmez — meta alandaki yer sınıf başlatıldığı an açılır, örnek sayısından
bağımsızdır.

`ThreadLocal` dördüncü bir örüntüdür: tuttuğu değer fiziksel olarak öbekte durur, ama her iş
parçacığı kendi kaydına erişir — erişim yolu iş parçacığının kendisinden geçer. Bu yüzden
sınıf olarak öbekte olsa bile davranış olarak çağrı çerçevesindeki bir değere benzer. Ama
ömürleri aynı değildir: yerel değişken kendi çerçevesi kapanınca yok olur, bir sonraki
çağrının hiçbir izini taşımaz. `ThreadLocal` kaydı ise iş parçacığı sürdüğü sürece kalır —
aynı iş parçacığı aynı yöntemi ikinci kez çağırdığında kaydı hâlâ oradadır, yeniden
yazılmadıkça bir önceki çağrıdan kalan değeri okur. "Yalnız" sütununa ikisi de girer, çünkü
ikisi de başka bir iş parçacığına görünmez; ama biri çağrıyla doğup çağrıyla ölür, öbürü
iş parçacığıyla birlikte yaşar.

Dizi ögesinin öbekte durması da aynı kuraldan gelir: Java Temelleri kursunun kurduğu gibi
dizi kendisi bir nesnedir, bu yüzden bir dizinin ögeleri de tıpkı bir nesnenin alanları gibi
öbekte durur ve aynı referans hangi iş parçacığına ulaşırsa o iş parçacığı da aynı ögelere
erişir.

- **JV8** — Bir değerin "paylaşılan" sayılması, yazan iş parçacığının bitmesi
  **beklendikten sonra** okunan bir değerle belirlenir (`join` ile); bitmeden okunan bir
  değer bu ölçüme girmez.
- **JV9** — Yerel değişken ve yöntem parametresi için "yalnız" sonucu bir gözlemden değil
  bir imkânsızlıktan gelir: başka bir iş parçacığının bu iki değeri okuyacağı hiçbir adres
  yoktur, dolayısıyla denenecek bir çağrı bile yazılamaz.
- **JV10** — Ölçülen altı değer aynı yazan iş parçacığı tarafından, aynı koşumda, aynı
  sırayla yazılır; hiçbiri ayrı bir koşumdan gelmez.
- **JV11** — Ortama bağlı hiçbir veri okunmaz: yığıt derinliği, öbek boyutu, adres
  yazılmaz; kimlik yalnız değer eşitliğiyle (`== 5`) okunur.

## Altı Değerin Üçü Yalnız, Üçü Paylaşılan

Ölçüm bir nesne yazar (`alan` ve `dizi` öbekte), bir sınıf statik alanı yazar (meta alanda),
bir `ThreadLocal` yazar, ve aynı iş parçacığının yerel bir değişkeni ile bir yöntem
parametresini yazar. Hepsi tek bir yazan iş parçacığında olur; okuma o iş parçacığı
bittikten sonra, ana iş parçacığından yapılır.

```java
// GorunurlukKutusu.java — bir nesne alani ve bir dizi ogesi tasir
class GorunurlukKutusu {
    int alan = 0;
    final int[] dizi = { 0 };
}
```

```java
// GorunenDegerler.java — dort yerdeki alti deger: kaci yazan is parciginin disina goruyor
import java.util.concurrent.CountDownLatch;

public class GorunenDegerler {
    static int statikAlan = 0;
    static final ThreadLocal<Integer> ozel = ThreadLocal.withInitial(() -> 0);
    static int yalniz = 0, paylasilan = 0;

    static void parametreYaz(int p, int[] hedef) { hedef[0] = p; }

    static void goren(String etiket, boolean paylasildi) {
        if (paylasildi) paylasilan++; else yalniz++;
        System.out.printf("%-26s %s%n", etiket, paylasildi ? "paylasilan" : "yalniz");
    }

    public static void main(String[] args) throws InterruptedException {
        GorunurlukKutusu kutu = new GorunurlukKutusu();
        CountDownLatch yazildi = new CountDownLatch(1);
        int[] parametreGorulen = { -1 };

        Thread yazan = new Thread(() -> {
            int yerel = 5;
            ozel.set(5);
            statikAlan = 5;
            kutu.alan = 5;
            kutu.dizi[0] = 5;
            parametreYaz(5, parametreGorulen);
            if (yerel != 5) throw new IllegalStateException();
            yazildi.countDown();
        });
        yazan.start();
        yazildi.await();
        yazan.join();

        // yerel degisken ve parametre: baska bir is parciginin bunlari okuyacagi hicbir
        // adres yok, dolayisiyla denenecek bir cagri bile yazilamaz.
        goren("yerel degisken", false);
        goren("yontem parametresi", false);
        goren("is parcacigina ozel deger", ozel.get() == 5);
        goren("nesne alani", kutu.alan == 5);
        goren("dizi ogesi", kutu.dizi[0] == 5);
        goren("statik alan", statikAlan == 5);
        System.out.printf("gorunurluk: %d yalniz, %d paylasilan%n", yalniz, paylasilan);
    }
}
```

```
yerel degisken             yalniz
yontem parametresi         yalniz
is parcacigina ozel deger  yalniz
nesne alani                paylasilan
dizi ogesi                 paylasilan
statik alan                paylasilan
gorunurluk: 3 yalniz, 3 paylasilan
```

Altı değerin **üçü** yazan iş parçacığının dışına hiç çıkmadı, **üçü** çıktı. İlk iki satır
hiç koşum gerektirmedi: `yerel` ve `parametreYaz`'ın parametresi yazan iş parçacığının kendi
çerçevesinde yaşar ve öldüğünde çerçeveyle birlikte yok olur; ana iş parçacığının bunları
okuyacağı bir değişken adı, bir alan, bir yöntem — hiçbiri yoktur. Koddaki
`if (yerel != 5) throw` satırı bunu doğrular: `yerel`in kendisi yalnız kendi çerçevesi
içinde, bir doğrulama olarak kullanılabilir; çerçeve dışına hiçbir biçimde aktarılmaz.
`parametreYaz` çağrısı ise parametre değerini `parametreGorulen` adlı paylaşılan bir diziye
**kopyalayarak** ana iş parçacığına taşıdı — ama taşınan şey parametrenin kendisi değil,
kopyasıdır; ölçüm bu kopyayı hiç okumadı, çünkü sorulan soru "değer başka bir yere
kopyalanabilir mi" değil "parametrenin durduğu yer başka bir iş parçacığına görünür mü"
sorusudur, ve yanıtı hayırdır.

Üçüncü satır koşum gerektirdi ve sonucu da aynı yöndeydi: `ozel.get()` ana iş parçacığında
çağrıldığında kendi `ThreadLocal` kaydını okur, yazan iş parçacığının kaydını değil; iki iş
parçacığının aynı adı taşıyan iki ayrı değeri vardır ve `5 == 0` yanlış çıkar. Son üç satır
ise `kutu.alan`, `kutu.dizi[0]` ve `statikAlan`'ın hepsinde `true` verdi: nesne öbekte tek
bir yerde durur, iki iş parçacığı da aynı referansı taşır; statik alan sınıfın kendi
alanında tek bir yerde durur, iki iş parçacığı da aynı sınıfa bakar.

## Nesneye Ait Alan ile Sınıfa Ait Alan Arasındaki Fark

Bir önceki ölçüm tek bir `GorunurlukKutusu` nesnesi kullandı; "öbekte tek bir yerde durmak"
ile "sınıfa ait alanda tek bir yerde durmak" aynı şey gibi görünebilir. Aradaki fark iki
nesne üretilince ortaya çıkar.

```java
// IkiOrnek.java — nesneye ait alan her ornekte ayri, sinifa ait alan tek bir yerde
public class IkiOrnek {
    public static void main(String[] args) {
        GorunurlukKutusu birinci = new GorunurlukKutusu();
        GorunurlukKutusu ikinci = new GorunurlukKutusu();
        birinci.alan = 1;
        ikinci.alan = 2;
        GorunenDegerler.statikAlan = 99;

        System.out.println("birinci.alan                : " + birinci.alan);
        System.out.println("ikinci.alan                 : " + ikinci.alan);
        System.out.println("iki nesnenin alani ayni mi  : " + (birinci.alan == ikinci.alan));
        System.out.println("iki nesne var, statikAlan yine de tek: " + GorunenDegerler.statikAlan);
    }
}
```

```
birinci.alan                : 1
ikinci.alan                 : 2
iki nesnenin alani ayni mi  : false
iki nesne var, statikAlan yine de tek: 99
```

İki `GorunurlukKutusu` nesnesi üretildiğinde `alan` alanından da iki ayrı kopya çıktı; biri
`1`, öbürü `2` tuttu ve ikisi eşit değil. `alan`, öbekte nesne başına bir yer kaplar — kaç
nesne üretilirse o kadar kopyası olur. `statikAlan` ise `GorunenDegerler` sınıfının kendi
alanıdır ve nesne sayısından bağımsızdır: sıfır nesne üretilse de var olurdu, iki nesne
üretilince de tek kalır. Önceki ölçümde "paylaşılan" sayılan üç satırın ikisi (nesne alanı,
dizi ögesi) paylaşılmayı **aynı nesneye referansı taşımaktan** alıyordu; üçüncüsü (statik
alan) paylaşılmayı **sınıfın kendisinden** alıyordu. İkisi de öbek ya da meta alanda tek bir
yerde durduğu için paylaşılıyor, ama "tek yer" ikisinde de farklı bir şeye bağlı: birinde
nesnenin kimliğine, öbüründe sınıfın kimliğine.

Bu fark yeni bir sınıf tasarlarken doğrudan bir sonuç doğurur: bir alanı bilerek paylaşılan
yapmak isteyen kod onu `static` yazar — o zaman paylaşım nesne sayısına bakmaksızın
kurulmuş olur; bir alanı yalnız kendi nesnesine bağlı tutmak isteyen kod ise onu örnek
alanı olarak bırakır ve nesneyi hiçbir zaman ikinci bir iş parçacığına aktarmaz. İki durumda
da JVM'in kendisi bir seçim yapmaz; alanın `static` olup olmadığı ve referansın paylaşılıp
paylaşılmadığı, ikisi de kaynak kodda yazılı bir karardır.

## Sınırlayıcı Ölçüm: Paylaşılan Olmak Görülecek Olmak Değildir

Yukarıdaki üç `paylasilan` satırı bir koşullu okumayla elde edildi: `yazan.join()`
çağrısı, yazma ile okuma arasına bir sıra koydu ve okuma yalnız yazma kesin bitince yapıldı.
Bu sıra olmasaydı — örneğin ana iş parçacığı `yazan.start()`'tan hemen sonra, `join`
çağırmadan `statikAlan`'ı okusaydı — aynı üç satırın ne vereceği **tanımsızdır**: yazan iş
parçacığının henüz yazmadığı eski değer (`0`) de görülebilir, yeni değer (`5`) de görülebilir.
Tek bir `int` yazması Java'da atomiktir, yani okunan değer yarı yazılmış bir çöp olmaz; asıl
sorun atomiklik değil **sıralamadır** — derleyicinin ve işlemcinin, gözlemlenebilir tek iş
parçacıklı davranışı bozmadığı sürece komutları yeniden sıralamasına izin verilir, ve bu
yeniden sıralama iki iş parçacığı arasında hangi yazmanın hangi okumadan önce sayılacağını
belirsiz bırakabilir. Bu, ölçülüp raporlanacak bir sayı değil, dilin **tanımsız** bıraktığı
bir durumdur; bu yüzden ders böyle bir okumayı çalıştırmaz, yalnız var olduğunu adlandırır —
bu kursun kuralı bir yarış koşulunu koşturmak değil, modellemektir.

Statik alan "paylaşılan" olarak sayıldı çünkü öbekte tek bir yerde duruyor ve iki iş
parçacığı da aynı adrese bakıyor — ama tek bir yerde durmak, o yerdeki en güncel değerin
**görüleceğinin** garantisi değildir. "Aynı yerde durmak" bir konum olgusudur ve derleme
zamanında bellidir; "görünür olmak" bir sıralama olgusudur ve yalnız çalışma zamanında,
aradaki sıralama aracına bağlı olarak kurulur. Görünürlüğün hangi kurala bağlı olduğu —
hangi yazmanın hangi okumadan önce sayılacağı, `volatile` ve kilit gibi araçların bu sırayı
nasıl garantilediği — Eşzamanlılık konusunun Java Bellek Modeli dersinin konusudur; bu ders
yalnız görünürlüğün **sıfırdan** kurulması gerektiğini, `join` gibi bir sıralama aracı
olmadan sıfır olduğunu gösterir.

Yığıt derinliği ve öbek boyutu bu derste ölçülmez: ikisi de çalıştığı makineye göre değişen
ortama bağlı verilerdir. Ölçülen tek şey bir değerin **kaç iş parçacığına** göründüğüdür —
konum bilgisi (dört yerden hangisi) derleme zamanında bellidir ve koşumdan koşuma değişmez;
görünürlük bilgisi (o konumdaki en güncel değerin okunup okunamayacağı) ise ancak doğru bir
sıralama aracıyla birlikte anlamlıdır ve bu ders onu yalnız aracın **var olduğu** durumda
ölçer.

## Özet

- Bir değer dört yerden birinde durur: yerel değişken ve parametre çağrı çerçevesinde,
  nesne alanı ve dizi ögesi öbekte, statik alan sınıfa ait alanda (meta alanda);
  `ThreadLocal` öbekte durur ama erişimi iş parçacığının kendisinden geçer.
- Bu depoda **yığın** bir veri yapısının adıdır, bellek alanı için **öbek** kullanılır.
- Altı ölçülen değerin üçü (yerel değişken, parametre, iş parçacığına özel değer) yazan iş
  parçacığının dışına hiç çıkmaz, üçü (nesne alanı, dizi ögesi, statik alan) çıkar.
- Yerel değişken ve parametre için "yalnız" sonucu bir gözlem değil bir imkânsızlıktır:
  başka bir iş parçacığının onları okuyacağı bir adres yoktur.
- Paylaşılan olmak görülecek olmak değildir: `join` gibi bir sıralama aracı olmadan aynı
  okumanın sonucu tanımsızdır; bu yüzden ders sırasız bir okumayı hiç çalıştırmaz.
- Yığıt derinliği ve öbek boyutu ortama bağlıdır ve ölçülmez.

## Sonraki Adım

Bu derste öbekte duran değerlerin hâlâ **erişilebilir** olduğu varsayıldı — `kutu` değişkeni
hep elde tutuldu, hiçbir referans bırakılmadı, `birinci` ve `ikinci` de `main`in kendi
çerçevesinde son satıra kadar canlı kaldı. Ama bir nesneye giden son referans de
kaybolabilir; program bir nesneyi bırakır, o nesneye artık hiçbir çerçeveden, hiçbir statik
alandan ulaşılamaz hâle gelir, ve öbekte artık kimsenin okuyamadığı bir alan kalır. Sıradaki
ders bu durumu ölçer: erişilebilirliğini yitiren bir nesnenin temizliğini hangi iş parçacığı
üstleniyor — ne çağıran, ne programın oluşturduğu bir iş parçacığı, kayıtta hiç olmayan bir
taraf.
