Başlangıçta büyük miktarda bellek ayırmak ve boşaltmak “belleği temizliyor” mu?


18

Kitap Kodlama Oyun Komple, Dördüncü Baskı , bölüm 5 ( Oyun Başlatma ve Kapatma ), bölüm Denetleme Bellek bu ilginç kod örneğini içerir:

bool CheckMemory(const DWORDLONG physicalRAMNeeded, const DWORDLONG virtualRAMNeeded)
{
    MEMORYSTATUSEX status; 
    GlobalMemoryStatusEx(&status);
    if (status.ullTotalPhys < physicalRAMNeeded) 
    {
        // you don’t have enough physical memory. Tell the player to go get a 
        // real computer and give this one to his mother. 
        GCC_ERROR("CheckMemory Failure: Not enough physical memory."); 
        return false;
    }
    // Check for enough free memory.
    if (status.ullAvailVirtual < virtualRAMNeeded) 
    {
        // you don’t have enough virtual memory available.
        // Tell the player to shut down the copy of Visual Studio running in the 
        // background, or whatever seems to be sucking the memory dry. 
        GCC_ERROR("CheckMemory Failure: Not enough virtual memory.");
        return false;
    }

    char *buff = GCC_NEW char[virtualRAMNeeded]; 
    if (buff)
    {
        delete[] buff;
    }
    else
    {
        // even though there is enough memory, it isn't available in one
        // block, which can be critical for games that manage their own memory 
        GCC_ERROR("CheckMemory Failure: Not enough contiguous memory."); 
        return false;
    }
}

Bu bazı soruları gündeme getiriyor.

İlk bölüm OS'ye (Windows) ne kadar fiziksel RAM'in mevcut olduğunu sorar. Meraklı kısım, büyük bir bellek parçası ayıran ve hemen boşaltan ikincisidir:

char *buff = GCC_NEW char[virtualRAMNeeded]; 
if (buff)
{
    delete[] buff;
}

Yazar açıklamaya devam ediyor:

... bu işlev büyük bir bellek bloğunu tahsis eder ve hemen serbest bırakır. Bu, Windows'un bellek yöneticisinde biriken çöpleri temizlemesini ve ihtiyacınız olduğu kadar bitişik bir blok ayırabileceğinizi iki kez kontrol etmesini sağlar. Çağrı başarılı olursa, esasen bir Zamboni makinesinin eşdeğerini sisteminizin hafızasında çalıştırırsınız ve oyununuzun buza çarpmasına hazır hale gelirsiniz ...

Ama bununla ilgili çekincelerim var.

"Bellek yöneticisinde biriken çöp temizleniyor mu?" Gerçekten mi? Eğer oyun yeni başlamışsa, hiç çöp olmamalı mı?

"Bitişik bir blok ayırabildiğinizden emin misiniz?" Belleği kendiniz yöneteceğiniz çok özel bir durumda, bu bir anlam ifade eder, ancak yine de, yarasanın çok fazla belleğini ayırırsanız, başka herhangi bir uygulamanın çalışmasını neredeyse imkansız hale getirirsiniz. sizinki açıkken sistem.

Ayrıca, bu işletim sistemini tüm bu belleği işlemeye zorlayacak ve sonuç olarak takas disk alanına çok fazla bellek çıkaracak ve uygulama başlangıcınızı çok yavaşlatacak mı?

Bu gerçekten iyi bir uygulama mı?


3
Çoğu modern işletim sistemi, bir uygulama geniş bir bellek alanı ayırdığında hiçbir şey yapmaz, iyimser tahsis kullanırlar ve siz belleği doldurana kadar aslında hiçbir şey yapmazlar, bunun potansiyel olarak yavaş bir işlem yapılmadan olmaktan başka bir şey yaptığını hayal edemiyorum
Vality

Ormanda uzun bir toprak şeridinin temizlenmesi, radyo, kulaklık vb. Tahtadan çıkarılması uçakların iniş yapmasına ve malzeme teslim etmesine neden oluyor mu?
Dan Neely

10
Komple Kodlama Oyun içeren çok değil-anlama-C ++ ve C-o-görünüyor-a-bit-C ++ gibi (aynı zamanda sonucu kontrol bu örnekte gösterildiği bir çok ile eşleştirilmiş saçmalıklar operator newiçin nullptr), beni izin verirse söylemek. Bu kitapla yapabileceğiniz en iyi şey bacalarınızı hafifletmektir. Ayırma ve tabii büyük bir hafızaya bloğunu azat etmez "temiz yukarı" bellek.
Damon

@Damon, kontrol etmedim, ama en azından küresel newoperatörü atmak yerine null döndürmek için aşırı yüklediklerinden şüpheliyim bad_alloc. Eğer yapmadılarsa, evet, bu kod daha saçma: P
glampert

1
@glampert: Durumun böyle olduğunu varsayarsak bile, bunu op-op olarak operator deletekabul etmek nullptrve tedavi etmek gerekir. Bunu yapmayan herhangi bir genel aşırı yük bozuldu. Yani her iki durumda da saçma. Tıpkı büyük bir bellek bloğu tahsis etmenin ve onu serbest bırakmanın "sihirli bir şekilde" iyi bir şey yapacağını varsaymak gibi. En iyi ihtimalle, herhangi bir zarar vermez (büyük olasılıkla, sayfalara dokunulmadığından ... aksi takdirde daha sonra yeniden yüklemeniz gereken bazı sayfaları çalışma grubunuzdan çıkarabilir).
Damon

Yanıtlar:


12

Belleğin büyük bir kısmını önceden tahsis olduğu tek şey olabilir bilgisayarınızın düşük RAM üzerinde olsaydı yapın, diske diğer programların bellek alanı parçalarını değiştirerek bazı ekstra alan boşaltmak için OS zorlamak olabilir.

Böyle bir takas genellikle, programınız gerçekleşirken neredeyse çok donan çok yavaş bir işlem olduğundan, yine de gerçekleşecekse , oyunun ortasında değil, oyunun başlamasından önce gerçekleşmesini sağlamanın bir avantajı olabilir .

Bununla birlikte, böyle bir değiş tokuşu diske zorlamak tam olarak% 100 güvenilir değildir:

  • Birçok sanal bellek uygulamasında, yalnızca bellek tahsisi aslında herhangi bir değiştirmeyi tetiklemez; bunun yerine, yalnızca ayırdığınız belleğin her sayfasına ilk kez eriştiğinizde olur. (Bu, varsayılan olarak olduğu gibi, aşırı bellek etkin olduğunda, Linux'un modern sürümleri için kesinlikle doğrudur; Windows'un farklı sürümlerinin nasıl işlediğinden emin değilim.)

    Bu nedenle, bu kodun gerçekten "belleği temizlemesini" istiyorsanız memset(), diziyi physicalRAMNeededserbest bırakmadan önce dizinin her bölümüne (veya en azından ilk baytına) gerçekte veri yazmak için muhtemelen bir çağrı veya eşdeğeri eklemelisiniz .

  • Ayrıca, işletim sistemini diğer programları RAM'den değiştirmeye zorlamak, bunun dışında kalacağı anlamına gelmez . Windows çok görevli bir işletim sistemidir ve bu takas edilen programlardan biri tekrar çalıştırmak ve takas edilen verilerini kullanmak istediği anda, oyununuzu tekrar dondurup tekrar takas eder.

    Bu nedenle, bu hile genellikle RAM sadece aktif olarak erişilemeyen büyük veri parçaları tarafından yeniliyorsa yararlıdır (örneğin bazı düzenleme yazılımlarında arka planda açık bırakılan büyük belgeler gibi). Web tarayıcıları bu konuda özellikle sorunlu olma eğilimindedir, çünkü aslında bazı arka plan sekmelerinde açılan bir web sayfasını kullanmasanız bile, sayfada hala RAM'de kalmaya zorlayan komut dosyaları olabilir.

    (Orada olan aslında RAM içine hafıza alanının bir kısmını kilitlemek için OS anlatmak ve onu dışarı takas edilmesini önlemek, ama bunlar genellikle yükseltilmiş ayrıcalık gerektiren bir program için yollar. Her durumda, sen yayınlanmıştır kodu olması görünmüyor bu tür yöntemleri kullanarak.)

Temel olarak, bu hüner kullanıcı o nispeten dar sınırda durumda tek kullanışlı görünüyor olacağını takas olmadan oyununuzu (ve aktif arka planda çalışan başka bir yazılım) çalıştırmak için yeterli RAM, ama bu RAM şu anda etkin ve kullanılmayan açık dosyalarla dolu veya oyununuz çalışırken diske değiştirilebilecek ve aktarılması gereken diğer veriler. Bu gibi durumlarda, oyun sırasında ara sıra küçük takas işlemlerini başlangıç ​​sırasında tek bir oyunla değiştirerek oyununuzun daha pürüzsüz ve daha duyarlı görünmesini sağlamak etkili olabilir .


1
Düşük düzeyli bellek yönetimi konusundaki sınırlı bilgimden, belirli bir sayfayı değiştirip değiştirmememe kararının çok daha karmaşık olduğunu ve sadece istenen bellek miktarından ve kullanılabilir bellek miktarından çok daha fazla faktörü dikkate aldığını söyleyebilirim. . Bunu aşırı derecede basitleştirmek ve genellikle varsayımlara güvenmek çok akıllıca değildir.
Panda Pijama

3
Bunların hepsinin işe yarayabilecek, işe yaramayacak ya da işe yarayacak gibi görünen, ancak tamamen ilgisiz nedenlerden ötürü hatırlamalarının önemli olduğunu düşünüyorum. Bildiğim kadarıyla, bu cevapta belirtilen davranışların hiçbiri belgelenmemiştir ve bunlara güvenmek akıllıca olmayacaktır. Bir işletim sistemi güncellemesi, ayar değişikliği, derleyici değişikliği veya hemen hemen her şey bu çalışmayı durdurabilir veya hatta performans üzerinde olumsuz bir etkiye sahip olabilir.
Panda Pijama

26

Bu yazının kaç yaşında olduğunu bilmiyorum, ama oldukça eski olduğunu söyleyebilirim. Modern Windows'da (XP ve daha yeni, ancak özellikle 64 bit sürümlerde), böyle bir şey yapmanın oyununuzun başlangıcında çok az olumsuz etkisi olacağını söyleyebilirim.

Her şeyden önce, adres alanının her işlem için sanallaştırıldığını unutmayın. İşleminiz söz konusu olduğunda, tüm adres alanınız kendinize aittir ve bu belleğin fiziksel olarak bitişik olup olmadığına bakılmaksızın her zaman bitişik (sanal) bellek elde edersiniz.

Aslında, fiziksel bellekte belleğin bitişik olup olmadığı kontrol ettiğiniz bir şey değildir. İşletim sistemi, fiziksel blokları uygun gördüğü şekilde nasıl atayacağınızı seçecektir ve uygulama düzeyinde yaptığınız hiçbir şeyin bitişik fiziksel belleğe sahip olmanın faydaları (varsa) üzerinde etkisi olabilir.

Çok uzun bir süre farklı boyutlarda bellek ayırmaya ve boşaltmaya devam ederseniz, sanal bellek parçalanmasına dikkat etmeniz gerekir. Bu, elbette 64 bit adres alanı ile çok daha az ilgilidir. Oyunlar genellikle aylarca çalışmaz, bu nedenle uzun süredir devam eden oyun sunucularından bahsetmedikçe, büyük olasılıkla bunu önemsemeniz gerekmez.

32-bit bir makinede çok farklı boyutlarda çok fazla bellek ayırsanız bile, modern bellek ayırmaları oldukça iyidir, bu yüzden aktif olarak aramadıkça sanal bellek parçalanması sorunları almanız olası değildir.

Size karşı dürüst olmak gerekirse, o yazarın ne hakkında olduğunu bilmiyorum. Adres alanı paylaşılsa ve fiziksel bellekte büyük bir bitişik blok alsanız bile, serbest bırakarak, artık umursamadığınızı söylüyorsunuz. Arka planda kendi tahsislerini yapan başka programlar da var, bu yüzden büyük mallocunuz başarılı olsa bile, kimse bir sonrakinin de başarılı olacağını garanti etmeyecek.

Bence bu "gerçekten anlamadığım bir nedenden ötürü çalıştı, bu yüzden açıklamak için bir şeyler yaptım" diye bir durum.


10
RAM, bitişik bloklara sahip olmanın herhangi bir şekilde "daha iyi" olmadığı dönen bir sabit disk gibi değildir. Bu doğru değil. bitişik RAM erişimi rastgele erişime göre daha hızlı bir büyüklük sırasıdır. RAM yongaları, belirli bir gecikme süresinin olduğu bölümlere ayrılır ve daha da önemlisi, L1 ve L2 önbellek özledikleri, belleğiniz dağıldığında performansınızı önemli ölçüde etkiler.
CaptainCodeman

@CaptainCodeman: Bunun benim bilgi alanımdan çıktığını kabul etmeliyim, ancak herhangi bir şekilde, bir Windows-uygulama-programcısı olarak, belleğinizin fiziksel olarak bitişik olup olmadığı üzerinde hiçbir kontrole sahip değilsiniz. Büyük bir bellek bloğu istemek çok fazla değişmeyecek.
Panda Pijama

@CaptainCodeman aslında bitişik sanal blok var bitişik mod 2 ^ RAM RAM önbellek hattı tahsisi nedeniyle hızlandıracak
cırcır ucube

8
@CaptainCodeman Evet, sıralı DRAM erişimi daha hızlı, ancak 4 KB (veya daha fazla) sayfalarda gerçekleşen sanal-> fiziksel haritadan bahsediyoruz, bu yüzden eşlemenin sıralı olup olmadığı bellek üzerinde çok fazla etkisi olmamalı okuma hızları. Ayrıca, önbellek önceden getirme ve bunun gibi şeyler fiziksel değil sanal adres alanında çalışır.
Nathan Reed

1
@NathanReed Yeterince adil ve açıklama için teşekkürler. RAM erişim hızının önerildiği gibi bellek alanında tamamen aynı olmadığını ifade ediyordum.
CaptainCodeman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.