Thread overview
diziler belleğe nasıl yerleştirilir ?
July 22, 2010

Benim düşüncelerim:

Benim bildiğim kadarıyla diziler belleğe sırasıyla yerleştirilir ve harcadığı alan ise toplam eleman(mı yoksa kapasite mi bilmiyorum ancak statik dizide farketmiyor.) çarpı eleman sayısı. Programda denedim ve statik dizilerde doğru sonuç verdi.

Ancak bunun aynısı dinamik diziler için doğru olamaz. Diziye ne kadar eleman ekleneceği belli olmadığından ne kadar yer ayrılacağıda belli olamaz. Örneğin 4 elemanlı a adlı bir int dizisi belleğe aktarıldığında sırasıyla belleğe yerleştirilsin. Ardından bir int yerleştirilsin. Ardından a dizisine eleman eklendiğinde nereye eklenecek ? Diziler liste olmadığı için bir sonraki elemanın nereye yerleşeceğini takip edemez ? O zaman tek bir çözüm kalıyor. Dizinin yerleştirilen başka boş bir alana yerleştirilecek ve ardından yeni eleman yerleştirilecek. Ancak bunu yazdığım bir programda en sonunda gözlemledim. Ancak anlamadığım bazı şeyler var:

import std.stdio;

import std.array;

void main()

{

   int[] a;

   int[] c = new int[5];

   int b;

   writeln("a kapasite: ",a.capacity);
// elemanı artsada hep aynı adresten başlıyor
  // ve b dizisi ile aralarında hep aynı sayıda bayt boşluğu var.
 // a dizisinin adresi neyi gösteriyor. Neyi depoluyor?
   writeln("b kapasite: ","yok normal birlik int");

   writeln("c kapasite: ",c.capacity);

   writefln("%d",&a);

   writefln("%d",&b);

   writefln("%d",&c);

   a~=0;

   writeln("ilk a : ", &a );



   foreach(i;0..10){

   writeln("---\n",i,"a kapasite: ",a.capacity);

   writeln("b kapasite: ","yok normal birlik int");

   writeln("c kapasite: ",c.capacity);

   writefln("%d",&a);

   writefln("%d",&b);

   writefln("%d",&c);

   a~=i;

   }

   writeln("a[8] : ", &a[8],"\na[0] : ",&a[0]);

}


Ayrıca capacity ne olduğunu şöyle düşündüm: capacity ilk adresten sonra kaç bit alanı daha o diziye verileceğini söylüyor. örneğin kapasitesi 4 olan ancak hiç elemanı olmayan bir a dizisi için adres şu şekilde olabilir:

00000000 // 1.eleman
00000004 //2.eleman
00000008 //3.eleman
0000000c //4.eleman başladığı yer.
0000000f//4.elemanın bittiği yer.
00000010 // başka bir elemanın başladığı yer.

Ancak bu adresler alındığı halde bu adreslere erişirken hata veriyor. Çünkü işleri boş ?

Not: dizilerin nereye yerleşeceğini ve hangi sırada yerleşeceğini derleyici mi karar veriyor yoksa işletim sistemi mi ? İşletim sistemi karar veriyorsa eğer sırasıyla yerleştirmezse(sanırım popüler olanlar sırasıyla yerleştiriyor.) nasıl sırayı takip edebiliyor ? (Örne dizi[2] adresinin yerini işletim sistemi nasıl bilebiliyor.) Derleyici ayrıca nasıl yer edinmek istediğini belirtiyor ?

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

July 24, 2010

Teşekkür anladım.

Bu belleğe yerleştirme yüzünden sanırım gösterge kullanmak şart. Örneğin bir liste tanımlarken yada bir ağaç yapısı tanımlarken şart ? Ağaç türünü göstergesiz yazamayız(Belki xml gibi yazarak göstergesiz yazarız ?) ?

Ben ağaç yapısına benzer bir yapıyı göstergesiz yazmaya çalıştım ancak olmadı.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

July 24, 2010

Alıntı (canalpay:1279798261):

>

Benim bildiğim kadarıyla diziler belleğe sırasıyla yerleştirilir ve harcadığı alan ise toplam eleman(mı yoksa kapasite mi bilmiyorum ancak statik dizide farketmiyor.)

Evet, sabit uzunluklu dizilerde kapasite ile uzunluk aynıdır. Hatta ikisi için de yer ayrılmasına gerek yoktur; çünkü bu bilgi derleme zamanında bellidir.

Alıntı:

>

çarpı eleman sayısı.

Tabii ki "eleman çarpı eleman sayısı" demek istemedin. Eleman sayısı çarpı eleman uzunluğu (.sizeof) olacak.

Alıntı:

>

Ancak bunun aynısı dinamik diziler için doğru olamaz. Diziye ne kadar eleman ekleneceği belli olmadığından ne kadar yer ayrılacağıda belli olamaz. Örneğin 4 elemanlı a adlı bir int dizisi belleğe aktarıldığında sırasıyla belleğe yerleştirilsin.

Yani 4 elemanı var; ama daha fazla eleman için kapasitesi olabilir. Sonrasını düşünüyor olabilir.

Alıntı:

>

Ardından bir int yerleştirilsin. Ardından a dizisine eleman eklendiğinde nereye eklenecek ? Diziler liste olmadığı için bir sonraki elemanın nereye yerleşeceğini takip edemez ? O zaman tek bir çözüm kalıyor. Dizinin yerleştirilen başka boş bir alana yerleştirilecek ve ardından yeni eleman yerleştirilecek.

Evet, dizinin elemanları bellekte her zaman için yan yana dururlar.

a) Kapasite dolana kadar, yeni eklenen elemanlar için yer var demektir.

b) Eğer kapasite dolmuşsa bile, yine de komşu belleğin kullanılmadığı durumlarda şanslıyız (Hani yakın zaman önce dizi kapasiteleriyle ilgili bir dmd hatası bulmuştuk; orada da bu anlatıldı: komşu bellek alanı boşsa, orası da bu dizinin kapasitesine eklenir)

c) Eğer komşu alan da doluysa, senin de söylediğin gibi, bütün elemanlara fazlasıyla yeten yeni bir yer ayrılır, var olan bütün elemanlar oraya kopyalanır; en sonunda da yeni eleman onların sonuna yerleştirilir

Alıntı:

>

Ancak bunu yazdığım bir programda en sonunda gözlemledim. Ancak anlamadığım bazı şeyler var:

> import std.stdio;
>
> import std.array;
>
> void main()
>
> {
>
>     int[] a;
>
>     int[] c = new int[5];
>
>     int b;
>
>     writeln("a kapasite: ",a.capacity);
> // elemanı artsada hep aynı adresten başlıyor
>    // ve b dizisi ile aralarında hep aynı sayıda bayt boşluğu var.
>   // a dizisinin adresi neyi gösteriyor. Neyi depoluyor?
>     writeln("b kapasite: ","yok normal birlik int");
>
>     writeln("c kapasite: ",c.capacity);
>
>     writefln("%d",&a);
>
>     writefln("%d",&b);
>
>     writefln("%d",&c);
> ```


a, b, ve c dizileri hiç yer değiştirmiyorlar. Gerektiğinde yer değiştirenler, *elemanlar*.

Üçünün de aslında dilim olduklarını biliyoruz. Yani dinamik dizilerle dilimler aynı şey. Her ikisinin kendi uzunluğu, yani tür olarak uzunluğu, her zaman için sekizdir (bir gösterge ve bir uzunluk):


import std.stdio;

void main()
{
int[] a = new int[1];
int[] b = new int[100];

bilgiVer("a", a);
bilgiVer("b", b);
}

void bilgiVer(string isim, ref int[] dizi)
{
writeln("isim : ", isim);
writeln("dizi türünün bayt olarak uzunluğu: ", dizi.sizeof);
writeln("dizideki eleman adedi : ", dizi.length);
writeln("dizinin adresi : ", &dizi);
writeln("dizideki ilk elemanın adresi : ", dizi.ptr);
writeln("&dizi[0] : ", &dizi[0]);
}



Bir çıktısı şöyle:

[code=x]isim                             : a
dizi türünün bayt olarak uzunluğu: 8
dizideki eleman adedi            : 1
dizinin adresi                   : BFF72AC8
dizideki ilk elemanın adresi     : 7F7E40
&dizi[0]                         : 7F7E40
isim                             : b
dizi türünün bayt olarak uzunluğu: 8
dizideki eleman adedi            : 100
dizinin adresi                   : BFF72AD0
dizideki ilk elemanın adresi     : 7F6800
&dizi[0]                         : 7F6800
[code]

Dikkat edersen, dizinin adresi ile ilk elemanının adresi farklı. İlk elemanının adresi iki yolla öğrenilebiliyor: dizi.ptr veya &dizi[0].

Bunun nedeni, dinamik dizilerin (veya dilimlerin) şöyle bir tür gibi düşünülebilmeleridir:


struct Dizi
{
int * ptr;
uint length;
}



O yüzden de dizi değişkeninin kendi uzunluğu hep sekiz çıkar. İçinde asıl elemanları gösteren bir gösterge, ve kaç eleman bulunduğunu gösteren bir uzunluk vardır. Kapasite bilgisi ise bellekten elemanlar için ayrılan yerin yakınında *gizli* bir yere yazılıyor.

O bilginin nereye yazıldığını std.array'in içine bakarak öğrenmeye çalışabiliriz. Ama bilginin çöp toplayıcıya ait bloktan edinildiği gibi bir izlenim edinebiliyorum: :)


_capacity = GC.sizeOf(pArray.ptr) / T.sizeof;



Alıntı:
> Ayrıca capacity ne olduğunu şöyle düşündüm: capacity ilk adresten sonra kaç bit alanı daha o diziye verileceğini söylüyor.

"Bit" dediğin için söylediğinden tam emin olamıyorum. Ama kapasitenin tanımı çok daha basit: şu ana kadar elinde bulunan belleğe kaç eleman sığdığı. Yani kapasite de eleman adedidir.

Uzunluğu 100, kapasitesi 120 olan bir diziye güvenle 20 adet eleman daha ekleyebiliriz demektir. Çünkü dizi bir noktada ilerisini düşünmüş ve fazladan elemanlar için yer ayırmıştır.

Yukarıda da dediğim gibi, kapasite dolsa bile, komşu alan boşsa, bütün komşu alanı da kendisine ayırarak kapasitesini çok uzuca arttırır.

Alıntı:
>  örneğin kapasitesi 4 olan ancak hiç elemanı olmayan bir  a dizisi için adres şu şekilde olabilir:
>
> 00000000 // 1.eleman
> 00000004 //2.eleman
> 00000008 //3.eleman
> 0000000c //4.eleman başladığı yer.
> 0000000f//4.elemanın bittiği yer.
> 00000010 // başka bir elemanın başladığı yer.
>
> Ancak bu adresler alındığı halde bu adreslere erişirken hata veriyor. Çünkü işleri boş ?

Kapasite, ilerideki elemanlar için ayrılan yerdir. Söylediğin kapasitesi 4 olan içinde elemanı bulunmayan diziyi şöyle gösterebiliriz:

00000000 // ileride 0 numaralı elemanın geleceği yer
00000004 // ileride 1 numaralı elemanın geleceği yer
00000008 // ileride 2 numaralı elemanın geleceği yer
0000000c // ileride 3 numaralı elemanın geleceği yer
(hepsi o kadar; eğer bundan sonrası müsaitse, 4 ve sonraki numaralı elemanlar buraya gelebilirler)

Dizinin kapasitesinin olması, elemanının olduğu anlamına gelmez. Elemanı olmayan dizide dizi[0] diyemeyiz.

Alıntı:
> Not: dizilerin nereye yerleşeceğini ve hangi sırada yerleşeceğini derleyici mi karar veriyor yoksa işletim sistemi mi ?

Derleyicinin programın içine gömdüğü kodlar (büyük olasılıkla da çöp toplayıcı) çalışma zamanında belirliyor. İşletim sistemi, istenen belleğin ne için kullanılacağını bilmez. O, yalnızca belirli büyüklükte parçalar (sanırım 4K kadar) olarak verir.

Alıntı:
> İşletim sistemi karar veriyorsa eğer sırasıyla yerleştirmezse(sanırım popüler olanlar sırasıyla yerleştiriyor.)

Dizilerin sırasız olması mümkün değildir. O veri yapısının tanımı gereği, bütün elemanlar bellekte yan yana dururlar.

Alıntı:
>  nasıl sırayı takip edebiliyor ? (Örne dizi[2] adresinin yerini işletim sistemi nasıl bilebiliyor.) Derleyici ayrıca nasıl yer edinmek istediğini belirtiyor ?

Çöp toplayıcı, işletim sisteminden çok büyük bir alanı bir seferde istiyor; ondan sonra, programın ihtiyaçları doğrultusunda bu alandan parça parça program için ayırıyor, işi bitenleri başka işler için kullanıyor... Daha da bellek gerekirse yine işletim sistemine danışıyor.

Ali

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
July 25, 2010

Evet, onlari gostergesiz yazmak cok ters olur. Dogalarina aykiri... :)

Heap denen veri yapisi da ikili agaca cok benzer ama o dizi olarak gerceklestirilir. Onu hatirlatirsan yuz yuze de konusuruz. :)

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]