Thread overview
Veri hafızadan temizlendiğinde fonksiyon çağırmak
Jul 14, 2013
Salih Dinçer
July 14, 2013
import std.stdio;
public import core.memory;

struct _int{
	int typ;
	int value;
	this(int typ, int value){
		this.typ = typ;
		this.value = value;
	}
}

enum{
M_INT
}
int main(string[] argv){
	for(int i; i<1_000_000; i++){
		new _int(M_INT, 1000);
	}
}

Burada 1 milyon tane _int oluşturulsa bile programın kullandığı ram hiç artmıyor 2 mb olarak sabit. Ama burada yeni bir veri oluşturuluyor ve daha sonra hafızadan siliniyor. Hafızadan silinme işlemi gerçekleştiği zaman x isminde bir fonksiyonu tetiklemek istiyorum.

delete(void* x) ~this() gibi özellikleri kullandım ama fayda etmedi

Zekeriya

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

July 15, 2013

Ali hocam, bu konuda dün akşam FB'de bayağ bir sohbet ettik...:)

Aslında kod tam olarak böyle değil ve Talha ile denediğimiz en son kod şu:

'(biraz sadeleştirdim...)'

import core.memory;
import std.conv, std.stdio;

struct _int{
   size_t typ;
   size_t value;
   this(size_t typ, size_t value){
       this.typ = typ;
       this.value = value;
   }
}

auto RhInt(size_t z){
 auto yer = new _int(0, z);
 return yer;
}

void main(string[] argv){
   size_t i, say = 1000;//000;
   _int * önceki;

   for(; i < say; i++){
     auto yeni = RhInt(i * 2 + 15);
     assert(önceki != yeni, to!string(i));
     önceki = yeni;
   }
   auto test = * önceki;
   if(test.value) writeln("Değerler yaşıyor olmalı, çünkü...");
   i.writeln(" kez çalıştı ve sonuncusunun değeri: ", test.value);
}/* Çıktısı:

Değerler yaşıyor olmalı, çünkü...
1000 kez çalıştı ve sonuncusunun değeri: 2013

*/

Ayrıca Talha en son şunu yazmış:

'(ben de yeni okuyorum...)'

Alıntı:

>

ama hocam bu 99 sayısı olmaz tam olarak
diyelim hafızadan silinmemesi gereken 200 tane veri var
yani değişken var o zaman ne olacak?
hocam şimdi öncelikle birkaç şeyi belirtmek isterim
bugün şunu öğrendim
malloc vs herhangi bir şekilde yer açtıktan sonra eğer adres bir şekilde programın bir yerinde bulunursa bu veriye çöp toplayıcılar müdahale etmez o veri hafızadan silinmez haliyle ben orada bu veriyi bir diziye atarsam ben diziden o veriyi silmediğim sürece
hafızzadan silinmeyecek
ben kendim o verinin kullanılıp kullanılmadığını da kontrol edemiyorum
ama bunu d nin kendisi yapabiliyor

Öncelikle 99 sayısı bir misaldi ve bunu dynamic hale (tıpkı dizilerin, belli bir capacity oranınca expand veya sonra üye kaybettiğinde shrink olmasına benzetebiliriz) çevirebiliriz ama önce passive yapmalıyız...

Benim aklıma, FB'de de söze döktüğüm gibi ilk olarak şu algoritma gelmişti ama geliştirilmesi lazım henüz çalışacak olgunluğa erişmiş değil:

class MemoryManagement {
 static Liste[] list;
 private size_t size, scanIndex;

 this(size_t memSize) {
   this.list = new Liste[memSize];
 }

 auto length() @property { return size; }
 auto getIndex() @property { return scanIndex; }

 bool setIndex(size_t index, bool set) @property {
   if(index >= this.size) return false;
   list[index].used = set;
   return true;
 }

 void updateIndex() @property {
   auto loop = scanIndex == this.size ? 0 : scanIndex;
   while(loop < this.size) {
     if( list[loop].used == false ) {
       scanIndex = loop;
       list[loop].used = true;
       break;
     }
   }
 }
}

Tabi bu sınıf gerçek bir Memory Management değil sadece basit bir denetleme birimi. Bunu asıl destroy() ile birlikte kullanmamız gerekiyor. Talhacığım, biraz daha sabret Ali hocamın eklemeleriyle iyi bir yere oturtacağız inşaallah...

Kolay gelsin...

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

July 15, 2013

Hocam şöyle bir deneme yaptım:

Alıntı:

>

GC.disable();
for(int i; i<1_000_000; i++){
new _int(M_INT, 1000);
}
while(1){}

Ve sonuç ne mi? RAM istikrarlı bir şekilde arttı ve arttı 1 gb ı buldu yani bu bellekten temizle işlemini bizim bu GC miz hallediyor peki bu GC çalıştığında benim fonksiyonumu çalıştırabilecek bir event var mı? Bunu da araştırdım ve bir event buldum

Alıntı:

>

// Typical C-style callback mechanism; the passed function
// is invoked with the user-supplied context pointer at a
// later point.
extern(C) void addCallback(void function(void*), void*);

// Allocate an object on the GC heap (this would usually be
)// some application-specific context data.
auto context = new Object;

// Make sure that it is not collected even if it is no
// longer referenced from D code (stack, GC heap, …).
GC.addRoot(cast(void*)context);

// Also ensure that a moving collector does not relocate
// the object.
GC.setAttr(cast(void*)context, GC.BlkAttr.NO_MOVE);

// Now context can be safely passed to the C library.
addCallback(&myHandler, cast(void*)context);

extern(C) void myHandler(void* ctx)
{
// Assuming that the callback is invoked only once, the
// added root can be removed again now to allow the GC
// to collect it later.
GC.removeRoot(ctx);
GC.clrAttr(ctx, GC.BlkAttr.NO_MOVE);

auto context = cast(Object)ctx;
// Use context here…

}

Peki sonucu mu soruyorsunuz? Derleem hatası :)

Error 1 Error 42: Symbol Undefined _addCallback C:\Users\TalhaZekeriya\Documents\GitHub\Script2.1\ConsoleApp1\ConsoleApp1\

Eğer event olursa bu işi çok daha basit bir şekilde karmaşık kodlar yazmadan halledebileceğimize inanıyorum. Çünkü yapmamız gereken tek şey şu olacak çöp toplayıcı çalıştığında bizim bu verimizi sileceği zaman silmesini engelleyip veriyi bir diziye atacağız. Daha sonra RhInt çağırıldığına bu dizide eleman olup olmadığını kontrol edeceğiz ve eğer elaman varsa bu diziden son elemanı alıp value sini yeni value ile değiştirip geri döndüreceğiz. İşlemler oldukça basit olur eğer bir event olursa :)

Ali hocam özetle çöp toplayıcıya biraz müdahale etmek , onu yönetmek istiyorum.

Alıntı:

>

Çalışma ortamı bellek gerektikçe ömrü tükenmiş olanların yerini yeni nesneler için kullanıyor.

Kesinlikle ama ben bunu kendim elle yaptırmak istiyorum.

Hocam eğer bu olayı yapabilirsek python dan daha hızlı matematiksel işlemler yapan bir dilimiz olacak :) Şu an için döngüler için yaptığım testlerde PHP ve PYTHON ı fazlasıyla geçti. Yeni nesne oluşturma işlemleri de aynı şekilde hızlanır ise eğer Rhodeus'un hızını tutabilene aşk olsun :)

Zekeriya

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

July 14, 2013

Kafam karıştı. :)

  • Veri hafızadan temizlenmez tabii ki. Yani, üzerini sıfırlamak gibi bir olay yok.

  • Belleğin başka bir amaçla kullanılması mümkün ama bu çöp toplayıcının bileceği bir iştir.

  • Nesne sonlanırken sonlandırıcı işlev çağrılır. Ancak, çalışma ortamının (D runtime) sorumluluğunda olan nesnelerin sonlandırıcılarının hangi anda işletileceği bilinmez. Eğer belirli bir anda işletilmesi isteniyorsa açıkça 'destroy(nesne)' yazılmalıdır. Başka bir yolu da nesneyi new ile oluşturmamaktır. (En sondaki notum da bununla ilgili.)

Tam olarak ne istediğini anlamadım.

Alıntı (zekeriyadurmus):

>
> import std.stdio;
> public import core.memory;
>
> struct _int{
> 	int typ;
> 	int value;
> 	this(int typ, int value){
> 		this.typ = typ;
> 		this.value = value;
> 	}
> }
>
> enum{
> M_INT
> }
> int main(string[] argv){
> 	for(int i; i<1_000_000; i++){
> 		new _int(M_INT, 1000);
> 	}
> }
> ```

>
> Burada 1 milyon tane _int oluşturulsa bile programın kullandığı ram hiç artmıyor 2 mb olarak sabit. Ama burada yeni bir veri oluşturuluyor ve daha sonra hafızadan siliniyor.

Yukarıda oluşturulan her nesneni ömrü tek satırlık. Çalışma ortamı bellek gerektikçe ömrü tükenmiş olanların yerini yeni nesneler için kullanıyor. Aslında o program tek _int'ten daha fazla yer harcamayabilir bile.

Alıntı:
> Hafızadan silinme işlemi gerçekleştiği zaman x isminde bir fonksiyonu tetiklemek istiyorum.

Sen nesne için sonlandırıcı işlevi (~this()) yazarsın ve x()'i onun içinden çağırırsın. Ancak yukarıda da dediğim gibi, sonlandırıcının ne zaman işletileceği çöp toplayıcıya kalmıştır. Tam istediğin anda işletilmesi için destroy()'u çağırmalısın. (En sondaki not da ilgili.)

Alıntı:
> delete(void* x)

D'de delete emekliye ayrıldı. delete C++'taki gibi iki iş hallederdi: Sonlandırıcıyı çağır ve belleği geri ver. D'deki destroy() bunlardan birincisini halleder.

Alıntı:
> ~this() gibi özellikleri kullandım ama fayda etmedi

Not: Benim de çok yakın zaman önce öğrendiğim bir şey var: D'nin şu anda kullandığı çöp toplayıcı yapıların sonlandırıcılarını hiç çağırmıyormuş. O yüzden tek çare destroy()'u açıkça çağırmak. :-/

Yalnız çok önemli bir nokta var: new yapı ayırdığında gösterge döndürür. O yüzden destroy()'a göstergeyi değil, nesneyi vermek gerekiyor:

import std.stdio;

struct S
{
~this() {
writeln("sonlandı");
}
}

S * foo()
{
auto s = new S();
return s;
}

void main()
{
auto s = foo();
destroy(*s); // <-- destroy(s) de derlenir ama yanlış olur!
}


Ali

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

Alıntı (zekeriyadurmus):

>

Alıntı:

>
GC.disable();

O çöp toplayıcının temizlik işlemlerini geciktirir ama bütünüyle engellemez. Çok gerektiğinde yine de temizlik yapmak zorunda kalır.

Alıntı:

>

Bunu da araştırdım ve bir event buldum

Eğer addCallback()'ten bahsediyorsan, o yalnızca o örnekte kullanılan ve bir C kütüphanesi tarafından hayalî bir işlevi temsil ediyor.

http://dlang.org/phobos/core_memory.html#.GC.addRoot

O örnekte söyledikleri şu: D tarafında bir bellek ayırdınız ve o belleği gösteren göstergeyi C tarafına vereceksiniz. Ne yazık ki D tarafındaki gösterge öldüğünde belleğin geri verilmesi tehlikesi var. O bellek uzun süre yaşamak zorunda olduğunda, yani C tarafı kullanmaya devam edecek olduğunda, addRoot() ile temizlenmesi engellenir.

Alıntı:

>

Eğer event olursa

Bildiğim kadarıyla yakın sürümlerden birisinde D'ye dışarıdan çöp toplayıcı eklemeye izin verilmeye başlandı. Hiç denemedim. Hatta belki de deneysel bir git kopyasında olan bir şeydir. Ama yukarıda gösterdiğin kod o değil.

Alıntı:

>

bu işi çok daha basit bir şekilde karmaşık kodlar yazmadan halledebileceğimize inanıyorum.

Bir nesnenin temizlik işlemleri başladığında (yoksa bittiğinde mi?) bu işten haberdar olmak istiyorsun öyle mi? Bunun olası olduğunu hiç sanmıyorum. Çöp toplayıcı nesnelerin temizleneceklerinin garantisini bile vermez.

Alıntı:

>

silmesini engelleyip veriyi bir diziye atacağız

Nesne referansını bir diziye baştan atmış olsan zaten çöp toplayıcı temizlemez.

Alıntı:

>

Ali hocam özetle çöp toplayıcıya biraz müdahale etmek , onu yönetmek istiyorum.

Yukarıda da dediğim gibi mümkün olabilir ama bütün çöp toplayıcıyı yazman gerekebilir. Ne yazık ki hiç kolay bir iş değil. DConf 2013'te çöp toplayıcı üzerine iki konuşma dinledik. İkisi de doktora tezi konusuydu. Senin yapamayacağını söylemiyorum ama olayın boyutunun bir örneği olarak almak gerek.

Alıntı:

>

Alıntı:

>

Çalışma ortamı bellek gerektikçe ömrü tükenmiş olanların yerini yeni nesneler için kullanıyor.

Kesinlikle ama ben bunu kendim elle yaptırmak istiyorum.

Bana yine de yapabilirsin gibi geliyor. Nesne yaşam süreçleri için çok yöntem var.

Ali

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