Pertanyaan Bagaimana cara kerja memori?


Saya mencoba untuk memahami kumpulan memori untuk manajemen memori, tetapi saya tidak dapat menemukan banyak hal tentang itu, meskipun tampaknya ini adalah mekanisme yang sangat umum.

Yang saya tahu tentang ini adalah bahwa "Kolam memori, juga disebut alokasi blok ukuran tetap" seperti memberitahu Wikipedia, dan saya dapat menggunakan potongan tersebut untuk mengalokasikan memori untuk objek saya>

Apakah ada spesifikasi standar tentang kolam memori?

Saya ingin tahu bagaimana ini bekerja di heap, bagaimana ini bisa diimplementasikan, dan bagaimana ini harus digunakan?

Contoh sederhana untuk menunjukkan bagaimana cara menggunakannya akan dihargai

EDIT

Apakah Pool itu?

Alokasi kolam renang adalah skema alokasi memori yang sangat cepat, tetapi   terbatas dalam penggunaannya. Untuk informasi lebih lanjut tentang alokasi kolam renang (juga   disebut penyimpanan terpisah sederhana, lihat konsep konsep dan Sederhana   Penyimpanan Terpisah).

dari pertanyaan ini

Saya bisa mengerti apa maksudnya, tapi itu tidak membantu saya memahami bagaimana saya bisa menggunakannya dan bagaimana kolam memori membantu aplikasi saya, bagaimana itu diimplementasikan


13
2018-05-28 13:36


asal


Jawaban:


Setiap jenis "pool" adalah benar-benar hanya sumber daya yang Anda peroleh / diinisialisasi sebelumnya sehingga mereka sudah siap untuk pergi, tidak dialokasikan dengan cepat dengan setiap permintaan klien. Ketika klien selesai menggunakannya, sumber daya kembali ke kolam bukannya dihancurkan.

Memori kolam pada dasarnya hanya memori yang telah Anda alokasikan sebelumnya (dan biasanya dalam blok besar). Misalnya, Anda mungkin mengalokasikan 4 kilobyte memori di muka. Ketika seorang klien meminta 64 byte memori, Anda hanya menyerahkannya sebuah penunjuk ke ruang yang tidak terpakai di kolam memori itu agar mereka membaca dan menulis apa pun yang mereka inginkan. Ketika klien selesai, Anda bisa menandai bagian memori itu sebagai tidak terpakai lagi.

Sebagai contoh dasar yang tidak mengganggu penyelarasan, keamanan, atau mengembalikan memori yang tidak terpakai (gratis) kembali ke kolam:

class MemoryPool
{
public:
    MemoryPool(): ptr(mem) 
    {
    }

    void* allocate(int mem_size)
    {
        assert((ptr + mem_size) <= (mem + sizeof mem) && "Pool exhausted!");
        void* mem = ptr;
        ptr += mem_size;
        return mem;
    }

private:
    MemoryPool(const MemoryPool&);
    MemoryPool& operator=(const MemoryPool&);   
    char mem[4096];
    char* ptr;
};

...
{
    MemoryPool pool;

    // Allocate an instance of `Foo` into a chunk returned by the memory pool.
    Foo* foo = new(pool.allocate(sizeof(Foo))) Foo;
    ...
    // Invoke the dtor manually since we used placement new.
    foo->~Foo();
}

Ini secara efektif hanya mengumpulkan memori dari tumpukan. Implementasi yang lebih maju mungkin menggabungkan blok-blok bersama dan melakukan beberapa percabangan untuk melihat apakah sebuah blok penuh untuk menghindari kehabisan memori, berurusan dengan potongan-potongan berukuran tetap yang merupakan kesatuan (daftar simpul saat bebas, memori untuk klien ketika digunakan), dan itu pasti perlu untuk menangani keselarasan (cara termudah hanya max sejajarkan blok memori dan tambahkan padding ke setiap bagian untuk menyelaraskan yang berikutnya).

Yang lebih mewah adalah pengalokasi teman, lembaran, yang menerapkan algoritma yang sesuai, dll. Menerapkan alokator tidak begitu berbeda dari struktur data, tetapi Anda mendapatkan lutut dalam bit mentah dan byte, harus memikirkan hal-hal seperti penyelarasan, dan dapat ' t mengocok isi di sekitar (tidak dapat membatalkan pointer yang ada ke memori yang digunakan). Seperti struktur data, tidak ada standar emas yang mengatakan, "Engkau harus melakukan ini". Ada berbagai macam, masing-masing dengan kekuatan dan kelemahan mereka sendiri, tetapi ada beberapa algoritma yang sangat populer untuk alokasi memori.

Menerapkan pengalokasi adalah sesuatu yang saya benar-benar akan merekomendasikan kepada banyak pengembang C dan C ++ hanya untuk mendapatkan selaras dengan cara manajemen memori bekerja sedikit lebih baik. Ini dapat membuat Anda sedikit lebih sadar tentang bagaimana memori yang diminta terhubung ke struktur data menggunakan mereka, dan juga membuka pintu baru peluang optimasi tanpa menggunakan struktur data baru. Hal ini juga dapat membuat struktur data seperti daftar tertaut yang biasanya tidak terlalu efisien jauh lebih bermanfaat dan mengurangi godaan untuk membuat buram / tipe abstrak menjadi kurang buram untuk menghindari tumpukan overhead. Namun, ada kegembiraan awal yang mungkin ingin menjadikan Anda alat penyalur khusus untuk segala sesuatunya, hanya untuk kemudian menyesali beban tambahan (terutama jika, dalam kegembiraan Anda, Anda lupa tentang masalah seperti keamanan dan penyelarasan benang). Layak membawanya ke sana dengan mudah. Seperti halnya mikro-optimasi, itu umumnya terbaik diterapkan discretely, di belakang, dan dengan profiler di tangan.


16
2018-05-28 22:57



Konsep dasar dari kolam memori adalah untuk mengalokasikan sebagian besar memori untuk aplikasi Anda, dan, kemudian, daripada menggunakan polos new untuk meminta memori dari O / S, Anda mengembalikan potongan memori yang sebelumnya dialokasikan sebagai gantinya.

Untuk membuat ini bekerja, Anda perlu mengelola penggunaan memori sendiri dan tidak dapat mengandalkan O / S; yaitu, Anda harus menerapkan versi Anda sendiri new dan delete, dan gunakan versi asli hanya ketika mengalokasikan, membebaskan, atau berpotensi mengubah ukuran memori Anda sendiri.

Pendekatan pertama adalah mendefinisikan Kelas sendiri yang merangkum kumpulan memori dan menyediakan metode khusus yang mengimplementasikan semantik new dan delete, tetapi mengambil memori dari kolam pra-dialokasikan. Ingat, kolam ini tidak lebih dari area memori yang telah dialokasikan new dan memiliki ukuran yang sewenang-wenang. Versi kolam renang dari new/delete kembali resp. ambil petunjuk. Versi paling sederhana mungkin akan terlihat seperti kode C:

void *MyPool::malloc(const size_t &size)
void MyPool::free(void *ptr)

Anda dapat merica ini dengan template untuk menambahkan konversi secara otomatis, mis.

template <typename T>
T *MyClass::malloc();

template <typename T>
void MyClass::free(T *ptr);

Perhatikan bahwa, berkat argumen template, size_t size argumen dapat dihilangkan karena kompilator memungkinkan Anda untuk menelepon sizeof(T) di malloc().

Mengembalikan penunjuk sederhana berarti bahwa kolam Anda hanya dapat tumbuh ketika ada memori yang berdekatan tersedia, dan hanya menyusut jika memori biliar di "batas" tidak diambil. Lebih khusus lagi, Anda tidak dapat memindahkan kolam karena itu akan membatalkan semua pointer fungsi malloc Anda kembali.

Cara untuk memperbaiki batasan ini adalah mengembalikan pointer ke pointer, yaitu, kembali T** bukan hanya T*. Yang memungkinkan Anda untuk mengubah pointer yang mendasari sementara bagian yang dihadapi pengguna tetap sama. Secara tidak sengaja, yang telah dilakukan untuk NeXT O / S, di mana ia disebut "pegangan". Untuk mengakses isi pegangan, seseorang harus menelepon (*handle)->method(), atau (**handle).method(). Akhirnya, Maf Vosburg menciptakan pseudo-operator yang dieksploitasi operator diutamakan untuk menyingkirkan (*handle)->method() sintaksis: handle[0]->method(); Itu disebut operator sprong.

Manfaat dari operasi ini adalah: Pertama, Anda menghindari biaya panggilan umum new dan delete, dan kedua, kolam memori Anda memastikan bahwa segmen memori yang berdekatan digunakan oleh aplikasi Anda, yaitu, ia menghindari fragmentasi memori dan karenanya meningkatkan cache cache CPU.

Jadi, pada dasarnya, kolam memori memberi Anda percepatan yang Anda peroleh dengan sisi negatif dari kode aplikasi yang berpotensi lebih kompleks. Tetapi sekali lagi, ada beberapa implementasi dari kolam memori yang terbukti dan dapat digunakan, seperti boost :: pool.


5
2018-05-28 13:53



Pada dasarnya, kolam memori memungkinkan Anda untuk menghindari beberapa biaya mengalokasikan memori dalam program yang mengalokasikan dan membebaskan memori sering. Apa yang Anda lakukan adalah mengalokasikan sebagian besar memori pada awal eksekusi, dan menggunakan kembali memori yang sama untuk alokasi berbeda yang tidak tumpang tindih secara temporal. Anda harus memiliki beberapa mekanisme untuk melacak memori apa yang tersedia dan menggunakan memori itu untuk alokasi. Setelah selesai dengan memori, alih-alih membebaskannya, tandai sebagai tersedia lagi.

Dengan kata lain, alih-alih panggilan ke new/malloc dan delete/free, membuat panggilan ke fungsi pengalokasi / deallocator yang ditentukan sendiri.

Melakukan hal ini memungkinkan Anda untuk hanya melakukan satu alokasi (dengan asumsi Anda tahu kira-kira berapa banyak memori yang Anda perlukan total) dalam proses eksekusi. Jika program Anda latensi- daripada terikat memori, Anda dapat menulis fungsi alokasi yang berkinerja lebih cepat daripada malloc dengan mengorbankan beberapa penggunaan memori.


1
2018-05-28 13:46