Apakah mengalokasikan dan membebaskan sejumlah besar memori pada saat startup "membersihkan memori?"

18

Buku Game Coding Complete, Edisi Keempat , bab 5 ( Inisialisasi Game dan Shutdown ), bagian Memeriksa Memori berisi contoh kode menarik ini:

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;
    }
}

Ini menimbulkan beberapa pertanyaan.

Bagian pertama hanya bertanya pada OS (Windows) berapa banyak RAM fisik yang tersedia. Bagian yang ingin tahu adalah yang kedua, yang mengalokasikan sejumlah besar memori dan membebaskannya segera:

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

Penulis kemudian menjelaskan:

... fungsi ini mengalokasikan dan segera melepaskan blok memori yang besar. Ini memiliki efek membuat Windows membersihkan semua sampah yang menumpuk di manajer memori dan memeriksa ulang apakah Anda dapat mengalokasikan blok yang berdekatan seluas yang Anda butuhkan. Jika panggilan berhasil, Anda pada dasarnya menjalankan mesin yang setara dengan Zamboni melalui memori sistem Anda, menyiapkannya untuk gim Anda ...

Tapi saya punya keberatan tentang itu.

"Membersihkan sampah yang menumpuk di manajer memori?" Betulkah? Jika permainan baru saja dimulai, tidakkah seharusnya tidak ada sampah?

"Memastikan kamu bisa mengalokasikan blok yang berdekatan?" Dalam kasus yang sangat spesifik di mana Anda akan mengelola memori sendiri, ini akan membuat mereka masuk akal, tapi tetap saja, jika Anda mengalokasikan banyak memori langsung dari kelelawar, Anda cukup banyak membuat tidak mungkin untuk aplikasi lain berjalan di sistem saat sistem Anda aktif.

Juga, bukankah ini akan memaksa OS untuk melakukan semua memori itu, dan sebagai akibatnya mengusir banyak memori ke ruang swap disk, banyak memperlambat startup aplikasi Anda?

Apakah ini benar-benar praktik yang baik?

Glampert
sumber
3
Sebagian besar OS modern tidak akan melakukan apa pun ketika aplikasi mengalokasikan area memori yang besar, mereka menggunakan alokasi optimis dan tidak benar-benar melakukan apa pun sampai Anda mengisi memori, saya tidak dapat membayangkan ini melakukan apa pun selain menjadi berpotensi no-op
Vality yang lambat
Apakah membersihkan sebidang tanah yang panjang di hutan, mengukir radio, headphone, dll. Dari kayu menghasilkan pendaratan pesawat dan mengirim pasokan?
Dan Neely
10
Game Coding Complete berisi banyak omong kosong yang dipasangkan dengan banyak yang tidak mengerti-C ++ dan C-yang-terlihat-agak-seperti-C ++ (juga diperagakan dalam sampel ini, memeriksa hasil operator newuntuk nullptr), jika Anda mengizinkan saya untuk mengatakan. Hal terbaik yang dapat Anda lakukan dengan buku itu adalah menyalakan cerobong asap Anda. Mengalokasikan dan membebaskan blok memori yang besar tentu saja tidak "membersihkan" memori.
Damon
@ Damon, saya tidak memeriksa, tapi saya kira mereka setidaknya kelebihan newoperator global untuk mengembalikan nol daripada melempar bad_alloc. Jika tidak, maka ya, kode ini bahkan lebih tidak masuk akal: P
glampert
1
@ glampert: Sekalipun dengan asumsi demikian, operator deletediperlukan untuk menerima nullptrdan memperlakukannya sebagai larangan . Setiap kelebihan global yang tidak melakukan itu rusak. Yang artinya tidak masuk akal. Sama seperti mengasumsikan bahwa mengalokasikan sejumlah besar memori dan melepaskannya akan "secara ajaib" melakukan sesuatu yang baik. Paling-paling, itu tidak akan membahayakan (kemungkinan besar, karena halaman bahkan tidak disentuh ... kalau tidak, mungkin swap keluar beberapa halaman dari set kerja Anda yang Anda perlu memuat ulang nanti).
Damon

Jawaban:

12

Satu hal yang pra-mengalokasikan sepotong besar memori bisa lakukan, jika komputer Anda rendah pada RAM, mungkin memaksa OS untuk membebaskan beberapa ruang tambahan dengan menukar bagian dari ruang memori program lain ke disk.

Karena bertukar seperti itu umumnya merupakan operasi yang sangat lambat yang cukup banyak membekukan program Anda saat itu terjadi, mungkin ada beberapa keuntungan untuk memastikan bahwa, jika itu akan terjadi, itu akan terjadi sebelum permainan Anda dimulai daripada di tengah-tengah gameplay.

Yang mengatakan, memaksa swap-ke-disk seperti ini tidak sepenuhnya dapat diandalkan 100%:

  • Pada banyak implementasi memori virtual, hanya mengalokasikan memori tidak benar-benar memicu swapping; melainkan, itu hanya terjadi ketika Anda pertama kali mengakses setiap halaman dari memori yang Anda alokasikan. (Hal ini tentu berlaku pada versi Linux modern, dengan memory overcommit diaktifkan, seperti pada umumnya; Saya tidak tahu pasti bagaimana berbagai versi Windows menanganinya.)

    Jadi, jika Anda benar-benar ingin kode ini "membersihkan memori", Anda mungkin harus menambahkan memset()panggilan atau yang setara untuk benar-benar menulis data ke setiap bagian array (atau setidaknya dengan physicalRAMNeededbyte pertama ) sebelum melepaskannya.

  • Juga, memaksa OS untuk program pertukaran lainnya keluar dari RAM seperti ini tidak berarti bahwa mereka akan tetap keluar dari itu. Windows adalah OS multitasking, dan segera setelah salah satu dari program yang ditukar itu ingin berjalan kembali dan untuk menggunakan data yang ditukar, ia akan ditukar kembali, berpotensi membekukan permainan Anda lagi.

    Dengan demikian, trik ini umumnya hanya berguna jika RAM sedang dimakan oleh potongan besar data yang tidak sedang diakses secara aktif (seperti dokumen besar dibiarkan terbuka di latar belakang dalam beberapa perangkat lunak pengeditan). Peramban web cenderung sangat bermasalah dalam hal ini, karena, bahkan jika Anda tidak benar-benar menggunakan laman web yang dibuka di beberapa tab latar belakang, laman tersebut mungkin masih memiliki skrip yang menjalankannya yang memaksanya disimpan dalam RAM.

    (Ada beberapa cara bagi sebuah program untuk benar-benar memberi tahu OS untuk mengunci sebagian ruang memorinya ke dalam RAM dan mencegahnya ditukar, tetapi ini biasanya membutuhkan hak istimewa yang lebih tinggi. Dalam kasus apa pun, kode yang Anda posting tampaknya tidak menggunakan metode seperti itu.)

Pada dasarnya, trik ini tampaknya hanya berguna dalam situasi batas yang relatif sempit di mana pengguna akan memiliki cukup RAM untuk menjalankan game Anda (dan perangkat lunak lain yang aktif berjalan di latar belakang) tanpa bertukar, tetapi RAM saat ini diisi dengan file terbuka yang tidak aktif dan tidak digunakan. atau data lain yang dapat dan harus ditukar ke disk saat game Anda berjalan. Dalam situasi seperti itu, ini mungkin efektif dalam membuat game Anda tampak lebih halus dan lebih responsif, dengan mengganti operasi swap kecil sesekali selama bermain game dengan operasi tunggal selama startup.

Ilmari Karonen
sumber
1
Dari pengetahuan saya yang terbatas tentang manajemen memori tingkat rendah, saya dapat mengatakan bahwa keputusan untuk menukar halaman tertentu jauh lebih kompleks, dan mempertimbangkan lebih banyak faktor daripada sekadar jumlah memori yang diminta dan jumlah memori yang tersedia . Terlalu menyederhanakan ini, dan umumnya mengandalkan anggapan tidak terlalu bijaksana.
Panda Pajama
3
Saya pikir penting untuk diingat bahwa semua ini adalah anggapan yang mungkin berhasil, bukan bekerja, atau tampaknya berhasil, tetapi untuk alasan yang sama sekali tidak terkait. Sejauh yang saya tahu, tidak ada perilaku yang ditunjukkan dalam jawaban ini yang didokumentasikan, dan tidak bijaksana untuk mengandalkan mereka. Pembaruan OS, perubahan pengaturan, perubahan kompiler, atau hampir semua hal dapat membuat ini berhenti bekerja, atau bahkan memiliki dampak negatif pada kinerja.
Panda Pajama
26

Saya tidak tahu berapa usia luncuran itu, tapi saya katakan sudah cukup tua. Di Windows modern (XP dan yang lebih baru, tetapi khususnya pada versi 64-bit), saya akan mengatakan melakukan sesuatu seperti itu akan berdampak kecil pada permulaan gim Anda.

Pertama-tama, ingatlah bahwa ruang alamat divirtualisasi untuk setiap proses. Sejauh menyangkut proses Anda, Anda memiliki seluruh ruang alamat untuk diri Anda sendiri, dan Anda akan selalu mendapatkan memori yang bersebelahan (virtual), terlepas dari apakah memori itu bersebelahan secara fisik atau tidak.

Faktanya, apakah memori itu bersebelahan atau tidak dalam memori fisik bukanlah sesuatu yang Anda kontrol. OS akan memilih bagaimana mengalokasikan blok fisik sesuai keinginan, dan tidak ada yang Anda lakukan pada level aplikasi yang dapat memengaruhi manfaat (jika ada) memiliki memori fisik yang berdekatan.

Anda harus peduli dengan fragmentasi memori virtual jika Anda terus mengalokasikan dan membebaskan memori dari berbagai ukuran untuk waktu yang sangat lama. Ini tentu saja jauh kurang relevan dengan ruang alamat 64-bit. Gim biasanya tidak berjalan berbulan-bulan, jadi Anda kemungkinan besar tidak perlu peduli tentang ini, kecuali jika kita berbicara tentang server gim yang berjalan lama.

Bahkan jika Anda mengalokasikan banyak memori dengan ukuran yang sangat berbeda di mesin 32-bit, alokasi memori modern cukup bagus, sehingga tidak mungkin Anda akan mendapatkan masalah fragmentasi memori virtual kecuali jika Anda secara aktif mencari mereka

Jujur dengan Anda, saya tidak tahu apa yang sedang terjadi tentang penulis itu. Bahkan jika ruang alamat dibagikan, dan Anda mendapatkan blok besar yang berdekatan dalam memori fisik, dengan membebaskannya, Anda mengatakan Anda tidak peduli lagi. Ada program lain yang berjalan di latar belakang melakukan alokasi mereka sendiri, jadi bahkan jika malloc besar Anda berhasil, tidak ada yang akan menjamin yang berikutnya akan berhasil juga.

Saya pikir itu adalah kasus "itu berhasil karena suatu alasan saya tidak begitu mengerti, jadi saya membuat sesuatu untuk menjelaskannya".

Piyama Panda
sumber
10
RAM tidak seperti hard disk berputar di mana memiliki blok yang berdekatan dengan cara apa pun "lebih baik" daripada tidak. Ini tidak benar. akses RAM yang berdekatan adalah urutan besarnya lebih cepat dari akses acak. Chip RAM dipecah menjadi beberapa bagian di mana ada sejumlah latensi untuk beralih, dan yang lebih penting, cache L1 dan L2 akan secara drastis memengaruhi kinerja Anda ketika memori Anda tersebar.
CaptainCodeman
@CaptainCodeman: Saya harus menerima yang keluar dari bidang pengetahuan saya, tetapi dengan cara apa pun, sebagai programmer -aplikasi Windows-aplikasi Anda tidak memiliki kendali atas apakah memori Anda secara fisik berdekatan atau tidak. Meminta blok memori yang besar tidak akan banyak berubah.
Panda Pyajama
@CaptainCodeman sebenarnya memiliki blok virtual yang berdekatan berada di berdekatan 2 mod 2 ^ N blok dalam RAM akan mempercepatnya karena alokasi baris cache
ratchet freak
8
@CaptainCodeman Ya, akses DRAM sekuensial lebih cepat, tetapi kita berbicara tentang pemetaan fisik virtual yang terjadi di halaman 4 KB (atau lebih), jadi apakah pemetaan itu berurutan atau tidak seharusnya tidak berdampak banyak pada memori kecepatan baca. Plus, prefetching cache dan hal-hal seperti itu beroperasi dalam ruang alamat virtual, bukan fisik.
Nathan Reed
1
@NathanReed Cukup adil, dan terima kasih atas klarifikasi. Saya baru saja menyatakan bahwa kecepatan akses RAM tidak sepenuhnya seragam di seluruh ruang memori, seperti yang disarankan.
CaptainCodeman