16 Mayıs 2009 Arşivi

Programımız hafızada kaç KB yer kaplıyor ?

// 16 Mayıs 2009 // 1 Yorum » // Delphi, Programlama

Yazdığımız programların hafızada ne kadar yer kapladıkları bilgisini elde etmenin pek çok yolu olmasına rağmen sanırım en iyi yöntem PSAPI.DLL içindeki metodları kullanmak. Bizim sevgili Delphi’miz sağolsun bu DLL’in içindeki metodları psAPI.pas(WinNT process API Interface Unit) içinde deklere etmiş. Bizlere sadece kullanmak kalıyor. Unit’i incelediğimizde pek çok yararlı metodun tanımlı olduğunu gözlemleyebiliyoruz. Processleri listeleyenlerinden tutunda, makinanızdaki device driverları listeleyen yada programınızın gereksiz kullandığı hafıza bloklarını serbest bırakmaya yarayacak bir diğer metod olan EmptyWorkingSet‘e kadar pek çok yararlı metod mevcut.(Bknz.)

Biz bu metodlardan GetProcessMemoryInfo isimli metodu kullanacağız makalemizde. Bu metod psAPI.pas’da aşağıdaki şekilde tanımlanmıştır:

function GetProcessMemoryInfo(Process: THandle;
  ppsmemCounters: PPROCESS_MEMORY_COUNTERS; cb: DWORD): BOOL;

(more…)

Nedir bu Thread’lerden çektiğimiz..!

// 16 Mayıs 2009 // 8 Yorum » // Delphi, Programlama

Uzun yıllık programcılık hayatımda pek çok defalar Thread kullandım ancak ilk defa bu kadar yoğun ve derinlemesine kullanma ihtiyacı hissettiğim bir projede çalıştım. Bu projemde TThread sınıfı ile uğraşırken karşılaştığım bazı sorunları sizlerle de paylaşmak istedim. Sizler önlemlerinizi baştan alın ki, saç baş yolmayın…

Eğer gerçekten time-critical işler yapıyorsanız thread’iniz içerisinde kesinlikle Synchronize kullanmayın.Çünkü Synchronize çağrısı thread’in çalışmasını kesip main thread’e geçirir.

Eğer siz TThread sınıfından türettiğiniz kendi sınıfınızda Execute metodunda bütün işi Synchronize metoduna teslim etmiş iseniz o zaman siz MTA (Multi Threaded Application) değil STA (Single Threaded Application) geliştiriyorsunuz demektir.. Yani ha formunuzun bir metodunu çağırmışsınız ha bir Thread create etmişsiniz.Arada hiçbir fark olmaz.! Bir örnek vermek gerekir ise:

TMyThread = class(TThread)
private
  fErrorString : String;
  procedure CallExternalProc;
protected
  procedure Execute; override;
public
  constructor Create;
  property ErrorString read fErrorString write fErrorString;
end;

constructor TMyThread.Create;
begin
  inherited Create(true); // Bekler vaziyette oluştur.!
  FreeOnTerminate := true; // Thread terminate olduğunda nesneyi Free et.!
  Resume; // Thread başlasın artık
end;

procedure TMyThread.CallExternalProc;
begin
  frmMain.Bilmemne;
  frmMain.BaskabirMetod;
  ...
  ...
 // Burada ise pek çok hesaplama vs. yaptığınızı düşünelim.!
end;

procedure TMyThread.Execute;
begin
  inherited;

  try
    Synchronize(CallExternalProc);
  except on E: Exception do
  begin
    ErrorString := Format('TMyThread: Error occured. %s, %s', [E.ClassType.ClassName, E.Message]);
  end;
end;

(more…)

Delphi Win32 & Lambda Expressions

// 16 Mayıs 2009 // 8 Yorum » // Delphi, Programlama

C# 3.0 ile birlikte gelen Lambda Expressionlar hakkında hemen hemen pek çok yerde makale yada yazıya rastlamak mümkün. Bu makalelerin bazılarında Lambda ifadelerin geleceğin programlama özelliği olduğu yönünde abartılı görüşler olsa da yine de faydalı ve olması gereken özellikler olduğu kanaatindeyim bende. Ancak bazı Lambdacıların da bilmesi gerekir ki bu programlama alemine kesinlikle yeni girmiş bir unsur değildir. Bazı programlama dillerinde bu yetenek çok uzun zamanlardan beri mevcut. Ancak maalesef Delphi’de henüz yok. En azından Win32 versiyonunda yok, Delphi Prism’de var.

O zaman bende kolları sıvadım ve tam anlamı ile Lambda Expressions gibi olmasa , onun gücüne yakınlaşamasa da, yine de benzer bir yapıyı kodlamak istedim. Lambda ifadelerinin genel kullanım amacı SQL sorgularında olduğu gibi bir veri kümesini filtrelemek olarak düşünülebilir. Bizde Delphi’de yazacağımız bir liste sınıfına bu özelliği kazandırmaya çalışacağız örneğimizde. Hatalarımız, eksiklerimiz olursa şimdiden affola diyerek başlayalım kodlamaya.

  TOperator = (opEqual, opGreater, opSmaller, opDifferent, opLike);

  TMyList = class(TList)
  public
    function Where(const PropertyName, PropertyValue : Variant; Operator : TOperator = opEqual) : TMyList;
    function InheritsFrom(const aClass : TClass) : TMyList;
  end;

(more…)

Uygulamamızın kullandığı hafıza miktarını nasıl düşürebiliriz ?

// 16 Mayıs 2009 // 8 Yorum » // Delphi, İşletim Sistemi, Programlama, Win32

Hepimizin bildiği gibi yazdığımız uygulamalar işletim sisteminde Process olarak adlandırılmaktadır. Her bir process en az bir main thread’e sahiptir. Bu iş parçacıkları, derlenmiş ikilik formattaki ham bilginin işletim sisteminin bellek yöneticisi vasıtası ile hafızaya yüklenerek işletilmesi ile hayat bulur. İşletim sistemlerinin bellek yönetimini nasıl yaptıkları son derece karmaşık bir konudur. Bir işletim sisteminde aynı anda birden fazla iş parçacığının çalışabilme ihtimali olduğu için bu işlemlerin bellekte kaplayacakları alanların ve bu bellek bölgeleri arasındaki etkileşimlerin son derece dikkatle hesaplanması gerekmektedir. İşletim sistemlerinde bir process fiziksel bellek ile iletişim halinde değildir. Bunun yerine her bir iş parçacığı için ayrılmış olan hafıza bloklarında her bir işlem kendisini fiziksel belleğin hakimi sanmaktadır. Bu tasarım, her bir işlem parçacığının teoride fiziksel belleğin kendisinden de daha fazla hafıza bloğuna sahip olabilmesini sağlamaktadır. Tüm bunları detaylıca anlatacak ne yerim ne de yeterince malümatım var ancak, bildiklerim ışığında izah etmeye devam edeyim. Process’lerin yani iş parçacıklarının fiziksel bellekten daha fazla alan kullanabilmesine imkan tanıyan teorik yaklaşıma Virtual Memory adı verilir. Virtual Memory modern işletim sistemlerinde disk vb. depolama cihazlarının kapasitelerinin bir kısmının fiziksel hafıza alanı gibi kullanması anlamına gelir. Örneğin Windows işletim sistemlerinde bu pagefile.sys dosyasıdır. İşletim sistemi bir iş parçacığının çalışması için gerekecek hafıza bloğunun karşılanamaması durumunda disk üzerindeki bahsi geçen dosyayı bir hafıza alanı gibi kullanarak fiziksel hafıza alanını rahatlatmaya çalışmaktadır. Ancak RAM’de tutulamayan verilerin sürekli disk ve RAM arasında yazılıp okunması elbette iş parçacığının çalışma performansını olumsuz yönde etkiler.

İşletim sistemleri, RAM ile sanal bellek arasındaki adreslemeleri fiziksel bellek haritasını kullanarak gerçekleştirirler. Her bir işlem için ayrılmış izole hafıza bloğundaki $101112 gibi bir adres fiziksel adresteki aynı adres demek değildir. Bu adresin fiziksel adresteki karşılığı başka bir tabloda tutulur ve fiziksel hafızaya erişim için bu tablodan istifade edilir. Modern işletim sistemleri, iş parçacıkları için ayırdıkları hafıza bloklarının tamamen izole olmasından sorumludurlar. Bir iş parçacığının diğer birisinin kullandığı hafıza bloğuna erişimi, o blokta yapabileceği değişiklikler tehlikeli durumlara sebebiyet verecektir. İşte bu sebeple arada sırada da olsa Protection Fault gibi hatalar alırız. Aynı zamanda işletim sistemleri, mevcut fiziksel hafızayı iş parçacıkları üzerinde adil dağıtma gibi bir misyonu da bünyelerinde barındırmak durumundadırlar.
(more…)