Record Allocation

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
kimimben
Üye
Mesajlar: 129
Kayıt: 28 Oca 2016 04:41
Konum: İstanbul

Record Allocation

Mesaj gönderen kimimben »

Merhaba

Aşağıda bir record tipini heap'de farklı yöntemlerle allocate etmeyi denedim.Şimdilik hata kontrolünü atladım.

Kod: Tümünü seç

program Project1;
 
{$APPTYPE CONSOLE}
{$R *.res}
 
uses
 System.SysUtils,
 WinApi.Windows;
 
type
 
 TPerson = record
   FirstName: string;
   LastName: string;
   Age: Byte;
 end;
 
 PPerson = ^TPerson;
 
var
 Person1: TPerson;
 Person2: PPerson;
 
 hHeap: Cardinal;
 
begin
 ReportMemoryLeaksOnShutdown := true;
 
 WriteLn('Person1 Stack Size :' + SizeOf(Person1).ToString());
 Person1.FirstName := 'kimim';
 Person1.LastName := 'ben';
 Person1.Age := 31;
 
 
 
 New(Person2);
 WriteLn('Person2 Stack Size :' + SizeOf(Person2).ToString());
 Person2^.FirstName := 'kimim';
 Person2^.LastName := 'ben';
 Person2^.Age := 31;
 WriteLn(Person2^.FirstName);
 WriteLn(Person2^.LastName);
 WriteLn(Person2^.Age);
 Dispose(Person2);
 
 
 
 hHeap := GetProcessHeap();
 Person2 := HeapAlloc(hHeap, HEAP_ZERO_MEMORY, SizeOf(TPerson));
 WriteLn('Person2 Stack Size :' + SizeOf(Person2).ToString());
 WriteLn('Person2 Heap Size :' + HeapSize(hHeap, 0, Person2).ToString());
 Person2^.FirstName := 'kimim';
 Person2^.LastName := 'ben';
 Person2^.Age := 31;
 
 WriteLn(Person2^.FirstName);
 WriteLn(Person2^.LastName);
 WriteLn(Person2^.Age);
 
 HeapFree(hHeap, 0, Person2);
 
 Readln;
 
end.

Çıktı :
Person1 Stack Size :12
Person2 Stack Size :4
kimim
ben
31
Person2 Stack Size :4
Person2 Heap Size :12
kimim
ben
31

Delphi'nin new methodunu mu kullanmak mantıklı, yoksa Windows api fonksiyonlarını mı ?
Avantaj dezanavantları neler olabilir ?
ertank
Kıdemli Üye
Mesajlar: 1665
Kayıt: 12 Eyl 2015 12:45

Re: Record Allocation

Mesaj gönderen ertank »

Merhaba,

HeapAlloc() ile karşınıza çıkacak en büyük sorunlardan birisi hafıza kaçaklarını yakalamak olur diye düşünüyorum. Belli noktalarda normalde manageable olan türler ile unmanageable türler bir araya geldiğinde bu gibi sorunlar ortaya çıkmaya başlayacaktır ve tespiti duruma göre oldukça zor olabilir. Mümkün olduğunca iki türdeki veri tiplerini HeapAlloc() kullanır iken tek bir record içinde bir arada kullanmamanızda fayda var. Örnek kod içinde aşağıdaki kısım hafıza kaçağına sebep olacaktır:

Kod: Tümünü seç

  hHeap := GetProcessHeap();
  Person2 := HeapAlloc(hHeap, HEAP_ZERO_MEMORY, SizeOf(TPerson));
  WriteLn('Person2 Stack Size :' + SizeOf(Person2).ToString());
  WriteLn('Person2 Heap Size :' + HeapSize(hHeap, 0, Person2).ToString());
  Person2^.FirstName := 'kimim';  // bu değişken HeapFree() çağırılmadan önce boşaltılmalı
  Person2^.LastName := 'ben';  // bu değişken HeapFree() çağırılmadan önce boşaltılmalı
  Person2^.Age := 31;
 
  WriteLn(Person2^.FirstName);
  WriteLn(Person2^.LastName);
  WriteLn(Person2^.Age);
 
  Person2^.FirstName := EmptyStr;  // değişken boşaltılması bu şekilde yapılabilir.
  Person2^.LastName := EmptyStr;  // değişken boşaltılması bu şekilde yapılabilir.
  HeapFree(hHeap, 0, Person2);
Büyük miktarlarda veriyi (3 milyon tane record) hafızada işlemeniz gerekli olacak durumlarda hafıza kullanımı önem taşımaya başlayacaktır. Bu gibi durumlarda record türünü "aligned edilmesin" şeklinde belirterek derleyicinin record tanımlarının hafıza kullanımını azaltmasını sağlayabilirsiniz.

Örnekte normalde FirstName ve LastName hafızada 4'er byte yer kaplar. Age ise sadece 1 byte kaplar. Ancak SizeOf(Person) 12 byte olur çünkü record türü "alligned" şeklindedir. x86 makinalarda örnek verilen record türü allign edilmediğinde hafızadan sadece 9 byte kullanacaktır. Derleyiciye record allign etmemesini "packed record" kullanımı ile bildiririz. Packed record kullanmanın bir dez avantajı: CPU packed record türünü daha yavaş işler. Ancak bu yavaşlık milyonlarca kayıt arasında işlem yaparken farkedilebilecek türdendir.

Özetle; hafızada çok yer kaplayan ve bu verileri çok hızlı bir şekilde işlemek gerektiği gibi durumlarda. Hatta bunların üzerine birkaç kıstas daha eklendiği özellikli uygulamalar için Windows APIleri kullanılabilir. Diğer tüm durumlar için programlama dilinin imkanlarını kullanılması tavsiye edilir.

Verilen örnek ile ilgili özel bir gereksinim yok ise; benzer aşağıdaki şekildeki bir kullanım kod okunabilirliği ve kullanım kolaylığı bakımından çok daha rahat olacaktır.

Kod: Tümünü seç

var
  Persons: TArray<TPerson>;
begin
  SetLength(Persons, 1);
  Persons[0].FirstName := 'My';  
  Persons[0].LastName := 'Name';
  Persons[0].Age := 31;
  Persons := nil;
Kullanıcı avatarı
kimimben
Üye
Mesajlar: 129
Kayıt: 28 Oca 2016 04:41
Konum: İstanbul

Re: Record Allocation

Mesaj gönderen kimimben »

Hocam aydınlandım bilgi için teşekkürler.
Fakat HeapFree den önce;

Kod: Tümünü seç

Person2^.LastName := EmptyStr;  // değişken boşaltılması bu şekilde yapılabilir.
Neden bu şekilde bir boşaltma yaptığımızı tam anlayamadım.
HeapFree hafızada ki bloğu boşatlmayacak mı ?
Kaçakları nasıl debug edebilirim ?
ertank
Kıdemli Üye
Mesajlar: 1665
Kayıt: 12 Eyl 2015 12:45

Re: Record Allocation

Mesaj gönderen ertank »

HeapAlloc dikkat ederseniz hafızadan sadece 12 veya 9 byte yer ayırıyor. Ancak siz string değişken içine teoride 2GB veri saklayabilirsiniz.

HeapFree hafızadan ayırdığı 12 veya 9 byte kısımı boşaltır. Ancak string için kullanılan ekstra byte'ları bilemez.

Kaçak debug etme konusu daha önce de belirttiğim gibi HeapAlloc() / HeapFree() kullanılan noktalarda zor. Verilen örnekte string değişken var ve bunun Free edilmeden önce boşaltılması gerekli. Ancak Record içinde de pointer vb kullanıldığı durumlar olursa? Bunların da ayrıca kontrolü gerekir.

Hafıza kaçağı tespiti için kodu ilk yazdığınızda hafıza kaçağına karşı test edip sorun yoksa ilerlemek tavsiye edilebilir. Ancak özetle HeapAllloc() / HeapFree() kullandığınız yerlerde hafıza kaçağı konusu tamamen programcının kendisinin alması gereken bir önlem oluyor.

Bu ve benzeri sebeplerden Delphi ile birlikte gelen özelliklerden faydalanmak en azından hafıza kaçağı konusunda çok büyük kolaylık olacaktır.
Kullanıcı avatarı
kimimben
Üye
Mesajlar: 129
Kayıt: 28 Oca 2016 04:41
Konum: İstanbul

Re: Record Allocation

Mesaj gönderen kimimben »

ertank yazdı: HeapFree hafızadan ayırdığı 12 veya 9 byte kısımı boşaltır. Ancak string için kullanılan ekstra byte'ları bilemez.
Aslında yazdığım örneğe göre; HeapAlloc sadece referans adresleri tutuyor.Ama gerçek veri heap'de başka bir hafıza bloğunda olduğu için, o hafıza bloklarınıda HeapFree çağırmadan önce temizlemem gerekiyor.

Kod: Tümünü seç

Person2^.LastName := EmptyStr;  // değişken boşaltılması bu şekilde yapılabilir.
Yani önce veriyi siliyorum, sonrasında verinin referans adresini siliyorum.
Doğrumu anladım hocam ?
ertank
Kıdemli Üye
Mesajlar: 1665
Kayıt: 12 Eyl 2015 12:45

Re: Record Allocation

Mesaj gönderen ertank »

Evet. Öyle oluyor.
Kullanıcı avatarı
kimimben
Üye
Mesajlar: 129
Kayıt: 28 Oca 2016 04:41
Konum: İstanbul

Re: Record Allocation

Mesaj gönderen kimimben »

Benim soruyu sormada ki amacım farklıydı.Ama daha başka şeylerin farkına vardım.
İlgi ve bilgi için teşekkürler hocam.
Cevapla