Gönderen Konu: Bellek Sorunları - Yaşanmış bir olaydan kesitler  (Okunma sayısı 9826 defa)

Hızlı düğmeleri aç

tesla

İleti: 426

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://
Yığın bellek parçalanması – Heap fragmentation

100 lerce megabyte boş belleğiniz olduğu halde altı üstü 5 mb için “new” - “malloc” dediğinizde “bad_alloc” aykırı durumu (exception) alıyorsanız anlaşılan o ki belleğiniz sorumsuz bellek yönetiminiz yüzünden kevgire dönmüş ve size peşi sıra dizilmiş 5mb’lık boş bir yer ayarlayamıyor!
ışte geçtiğimiz Cuma başıma gelen tam da buydu.  Aslında her oyun geliştirme kitabında bu konuyla ilgili bir bölüm olur. Zaten gigabytlar dolusu yeri ben nasıl doldurayım deyip çok sallamadan geçerdim. Ama gel gör ki başa geldi, başa gelince atladığım yerleri tekrardan bir üzerinden geçtim =) bir musibet bin nasihat hesabı.

Hemen neler olup bittiğini daha iyi anlamak için bir araç aradım ve VMMap’i buldum. Gerçekten çok başarılı bir araç, bellek sorununuz olsun olmasın programınızın neler çevirdiğini daha iyi anlamanız için her zaman kullanılabilecek bir araç. (Daha detaylısı için bkz. WinDbg)

VMMap’ten “free memory” ‘yi seçip, büyüklüğe göre sıraladığınızda kullanabileceğiniz boş bellek bloklarını görebilirsiniz. Tüm boş bellek blokları toplamı yüzlerce MB edebilir ama bir seferde alabileceğiniz en büyük miktar ordaki en büyük blok kadardır (ben öyle anladım). Benim durumumda 3, 5 MB’lardan oluşan yaklaşık 200 MB’lık bir alanım vardı ama 5 MB’dan büyük bir .tga yüklerken göçüyordu sistem.



Ekran görüntüsünde “Free Space” seçilmiş “Size”’a göre sıralanmış ve en büyük bellek parçasının 2048 byte olduğu görülüyor ama toplamda 61 MB boş yerimiz var. ışte bu gibi durumlarda 3 MB’lık bir texture yükleme bizi cortlatıyor. Aslında görev yöneticisinden bakarsak daha bir kaç GB daha sanal belleğimiz (virtual memory) var  ama bizim uygulamamız için ayrılan maksimum sınır 2GB olduğu için bizim şimdilik 61 MB’ımız var görünüyor.

Kullandığımız oyun motoru kör topal da olsa çalışan ve epey bir yıldır kullanılan bir sistem. (Image Space Corp. tarafından yazılmış). Çok mecbur kalmadıkça motoru değiştirmememiz gerekiyor, bu yüzden kitaplarda bahsi geçen yöntemleri uygulamam pek mümkün değildi. Aslında motorun kendi bellek yöneticisi var ama aktif değildi, ilk deneme olarak onu aktifleştirdim. Yorum satırlarının yalancısıyım, dediğine göre talep edilenden biraz daha büyük bellek blokları alıp, yeri gelince kaydırma yapıp bu parçalanma sorunlarını azaltıyormuş. Dediği gibi de yaptı ama durum daha kötüye gitti nerdeyse hiç boş yer kalmadı, görev yöneticisinden bakarsak daha yerimiz var ama VMMap öyle demiyordu. Tek bir ipucu vardı, her seferinde 2GB civarına bir üst limite takılıyorduk, peki neden 2GB? Bu soru üzerine google’dan gelen ilk sonuçlar dikkat çekiciydi...

Devam edecek...

Bellek Sorunları - Yaşanmış bir olaydan kesitler

« Yanıtla #1 : 17.11.2011 13:36:44 »
Hızlı düğmeleri aç

tesla

İleti: 426

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://
Windows için bellek sınırları

Burda tüm windows sürümleri için görevler (process) için tanımlanan maksimum bellek sınırları belirtilmiş. Ordaki tablo daha iyi özetlemiş ama kısaca tekrar yazarsak. 32 bitlik sistemlerde görevler için verilen sanal bellek sınırı 2 GB. 4-gigabyte tuning denen bir ayar çekme yöntemiyle bu sınırı 3 GB’a kadar öteleyebiliyoruz. Bu ayarı windows’a çekiyoruz, windows’un başlangıç parametrelerine (boot parameters) “/3GB” anahtarını eklememiz kafi. Ben 32-bit Windows 7 için yaptım, boşuna windows’un kurulu olduğu yerde “Boot” dosyasını aramayın, artık öyle ulu orta duran bir dosya değil(miş). Yönetici hakları ile:
Kod: [Seç]
bcdedit /set IncreaseUserVa 3072 diyerek Boot kütüğüne gerekli parametreyi girmiş oluyoruz. (3072 Byte == 3 GB ) . Ama sıkıntımız bitmiyor, windows’tan izin aldık ama programımızın da bundan haberdar olması lazım, yoksa o efendi efendi takılır ve 2 GB kullanmaya devam eder. Çalışan programların “IMAGE_FILE_LARGE_ADDRESS_AWARE” etiketi ayarlı olması lazım. Yani çalışan program windows’a, patron izin varsa daha fazla bellek kullanmak isterim demesi lazım. Bunu programı oluştururken  bağlama (linker) parametresi ile yapabilirsiniz. Visual Studio için linker ayarlarından “Linker->System->Enable Large Addresses” ‘tan “Yes (/LARGEADDRESSAWARE)” diyoruz. Zaten derlenmiş bir programsa ve tekrar derleme şansınız yoksa o zaman şu gibi araçlarla programınızı yamalayabilirsiniz.(patch) (her bulduğunuzu kullanmayın, araya keylogger atarsa facebook şifreniz gider yazık olur :P)

Gelelim 64 bit Windows’lara. Orda işler daha rahat, Windows siz aksini belirtmedikçe daha fazla bellek vermeye niyetli. Yani Windows ayarlarından bir şeyleri değiştirmenize gerek yok. 64 bit Windows’larda hem 32 bit hem 64 bit programlar çalıştırabildiğimiz için durum ikiye ayrılıyor. 64 bit Windows’ta 32 bit programlar için varsayılan ayar gene 2 GB ama programınızı yukarda anlatıldığı şekilde derler yada yamalarsanız 4 GB ’a kadar hakkınız oluyor. (Zaten 32 bit sistemler için fiziksel bellek sınırı).

64 bit Windows’ta 64 bit programların varsayılan olarak 8 TB’a kadar hakkı var. 8 TB teorik bir limit çünkü sunucu olmayan Windows’ların maksimum limiti 192 GB. Ama yok o kadar da uçmasın derseniz bu sefer programınızın IMAGE_FILE_LARGE_ADDRESS_AWARE etiketini kapalı duruma getirirseniz çalışan görevler-programlar 2 GB limitli bellek kullanır.

Belki zaten bilmiş olduğunuz şeylerin üzerinden belki de yanlışlar yaparak üzerinden şöyle bir geçtim. Benim açımdan böylece bellek sorunu tek satır kod eklemeden çözülmüş oldu. Ekip olarak programı fazla adres kullancak şekilde derlemeye karar verdik. Artık bad_alloc aykırı durumu almıyoruz, bellek parçalanması da şimdilik ciddi bir tehdit oluşturmuyor yoksa 1 gün boyunca açık bırakılan programın bir yerde eninde sonunda çakılması lazımdı. Zaten bu çözümden sonra gelen garip hata raporları da birden kesildi...

Ve sonrasında gelen güzel gibi bir hafta sonu, Battlefield 3'te otların arasına tüneyip emekli keskin nişancı modunda takılmak paha biçilemez :D

Bellek Sorunları - Yaşanmış bir olaydan kesitler

« Yanıtla #2 : 17.11.2011 16:59:54 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
Seninle daha önce konuşmuştuk zaten bu konuyu. Ama detaylarını da öğrenmiş oldum böylece sağol. şimdi olaya pozitif yaklaşabilirim ancak burası bir scene forumu olduğu için...
 
2 GB BELLEK YETMEDı Mı!!!!!!!!!!!!!!!!!!!!!!
 
Demek durumundayım ehehehe. Sen kesin bunu okumuşsundur da şimdi. :)
 
http://www.howzatt.demon.co.uk/articles/OutOfMemory.html

Bellek Sorunları - Yaşanmış bir olaydan kesitler

« Yanıtla #3 : 17.11.2011 20:51:11 »
Hızlı düğmeleri aç

nightlord

İleti: 1.085

Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.nightnetwork.org

Bellek Sorunları - Yaşanmış bir olaydan kesitler

« Yanıtla #4 : 18.11.2011 00:50:25 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
@tesla: Bu arada aklıma gelmişken, bütün textureları/modelleri memory'de tutup, gerektikçe ekran kartına gönderip siliyorsunuz di mi? Daha doğrusu bunu sizin yerinize kullandığıniz engine yapıyor olsa gerek. Ama kullanılmayan texturelar da sürekli hafızada kalıyor anladığım kadarıyla. ID Tech 5'de elemanlar 1000000x1000000 pixellik tek bir texture'ı stream loading ile kullanıyorlardı. Hani böyle birşeye kalkışın demiyorum, yanlış anlama. :) Sadece arada bir hdd hareketi engine'i öldürmeyecektir diye umuyorum. En azından oyunun mapini birkaç region'a bölüp, her region giriş ve çıkışında gereksiz textureları uçurup, gereklileri yükletebilirsiniz. Kolay olmayabilir, hele ki hazır engine kullandığınız durumda. Ama basit de olsa bir çözüm yoludur. Tabii engine zaten böyle şeyler yapıyor olabilir. Ancak sen 2 GB yetmiyor dediğinde böyle bir sorun olmasından kıllandım. :)

Bellek Sorunları - Yaşanmış bir olaydan kesitler

« Yanıtla #5 : 22.11.2011 17:14:05 »
Hızlı düğmeleri aç

tesla

İleti: 426

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://
@skate
Skate senin gönderdiğin benim yazıya benzemiş, kullandığımız araçlar bile örtüşüyor. Hatta elemanlar da virtual 64-bit makine kullanalım olsun bitsin demişler sonunda :) .. (yalnız neden virtual orasını anlamadım)

Bu arada dediğin gibi, büyükçe bir harita var, sorun genelde o haritada oluyor. Aynen dediğin gibi texture'lar kullanılsın kullanılmasın sürekli bellekte duruyor. "Kullanılmayan-görünmeyen yerleri sil" gibi bir mekanizma ise şuan eklenmeyecek kadar karmaşık duruyor.

Ufak bir detay olarak, "new"'i aykırı durum fırlatmadan kullanmak için "std:nothrow" ile kullanabiliyormuşuz, [Effective C++, 49. madde]
Bu baya işe yaradı, try-catch'e bulaşmadan bellek sorunu olursa assert gönderip, log yazdırabiliyoruz.

Mesela aşağıdaki kod "std::nothrow"'suz haliyle kullanılıyormuş, hiçbir zaman o "if" bloğuna girmiyormuş, çünkü "new"'de aykırı durum(exception) üretip ordan çağrıldığı yere kadar geri dönüydu. O yüzden hatanın ne olduğu bile anlaşılmıyordu, .dmp dosyası da 0 Kb olarak çıkıyordu. şimdi bellek sorunu olursa en azından haberimiz var.

Kod: [Seç]

// eski: char* mem = new char[size];
char* mem = new (std::nothrow) char[size];

if(mem == 0)
{
  log(...);
  assert(...);
}


ID-Tech 5'e gelince, id Software bu mega texture olayına taktı zaten. Yalnız Rage'te texture sorunları var diyorlardı. Yani motorun en önemli özelliği bu mega texture olayı, onun da problemli olması iyi değil tabi. Texture stream-mtream hava cıva demek ki hehe :P (şaka tabi, id Soft'a laf yok. Zaten Carmack demoscene'e giricem 64k yapıcam diyordu, belki bu foruma bile gelir :P)

@nightlord
Dökümanın tepesinde Andrei Alexandrescu görünce aha dedim sağlam bir şeyler geliyor, muhtemelen bir çok yerini anlamayacam. Neyse çift kolonlu akademik makale perdesi arkadasında sade bir dille yazıldığı için baya anlaşılır çıktı.
(bu çift kolon ve akademik dil belası yüzünden tez 2 sefer direkten döndü, o gun bu gün öyle bir gıcığım ki bu makalelere, görünce yırtasım geliyor :))

Bellek Sorunları - Yaşanmış bir olaydan kesitler

« Yanıtla #6 : 22.11.2011 19:55:57 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
std::nothrow'u hatırlattığın iyi oldu. daha önce de görmüştüm ancak hiç kullanmamıştım. uzunca bir süre C++/CLI kullandığım ve Native C++ kullanmaya ara verdiğim için de pek gerekmiyordu açıkçası. şimdi DirectShow sayesinde yeniden daldığım için Native C++ dünyasına, kullanmamda yarar var.

Bellek Sorunları - Yaşanmış bir olaydan kesitler

« Yanıtla #7 : 23.11.2011 00:43:55 »
Hızlı düğmeleri aç

nightlord

İleti: 1.085

Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.nightnetwork.org
exception atan new iyidir iyi :) (tabii RAII ile beraber)