avatar of 发明者量化-小小梦 发明者量化-小小梦
fokus pada Pesan pribadi
4
fokus pada
1271
Pengikut

Poin pengetahuan penulisan strategi C++: Daur ulang memori C++

Dibuat di: 2017-12-29 11:00:02, diperbarui pada: 2017-12-29 11:25:11
comments   0
hits   3111

Poin pengetahuan penulisan strategi C++: Daur ulang memori C++

Sebelum menulis strategi C++, Anda harus memiliki pengetahuan dasar, tidak perlu menjadi ahli dalam bahasa C, setidaknya Anda harus tahu aturan-aturan ini. Berikut ini adalah transkripnya:

  • #### C++ Memori Object Conflict

  Jika seseorang menyebut dirinya seorang programmer yang tidak tahu apa-apa tentang memori, maka saya dapat memberi tahu Anda bahwa dia pasti membual. Menulis program dengan C atau C++ membutuhkan perhatian yang lebih besar terhadap memori, bukan hanya karena alokasi memori yang wajar secara langsung mempengaruhi efisiensi dan kinerja program, tetapi lebih dari itu, masalah dapat terjadi secara tidak sengaja ketika kita mengoperasikan memori, dan seringkali masalah ini tidak mudah ditemukan, seperti kebocoran memori, seperti pin yang tergantung. Penulis tidak di sini hari ini untuk membahas cara menghindari masalah ini, tetapi ingin mengenal objek memori C++ dari sudut pandang lain.

Kita tahu bahwa C++ membagi memori menjadi tiga wilayah logis: stack, heap, dan static storage area. Karena itu, saya menyebut objek yang berada di antara mereka masing-masing sebagai heap object, heap object, dan static object. Lalu apa perbedaan antara berbagai objek memori ini? Apa kelebihan dan kekurangan masing-masing objek heap dan heap? Bagaimana melarang pembuatan objek heap atau heap?

  • 1 Konsep dasar

    Perhatikan , yang biasanya digunakan untuk menyimpan variabel lokal atau objek, seperti objek yang kita deklarasikan dalam definisi fungsi dengan kalimat seperti berikut:

    Type stack_object ; 
    

    stack_object adalah sebuah obyek stack, yang hidupnya dimulai dari titik definisi, dan berakhir ketika fungsi yang ditempatkannya dikembalikan.

    Selain itu, hampir semua temporary object adalah frame object. Sebagai contoh, fungsi yang didefinisikan sebagai berikut:

    Type fun(Type object);
    

    Fungsi ini menghasilkan setidaknya dua temporary object, pertama, argumen yang diteruskan dengan nilai, sehingga akan memanggil fungsi copy constructor untuk menghasilkan sebuah temporary object object_copy1, yang digunakan dalam fungsi yang digunakan bukan object, tetapi object_copy1, tentu saja, object_copy1 adalah sebuah objek frame, yang akan dilepaskan saat fungsi kembali; dan fungsi ini adalah nilai yang dikembalikan, ketika fungsi kembali, jika kita tidak mempertimbangkan kembali nilai optimasi ((NRV), maka akan menghasilkan sebuah temporary object object_copy2, yang akan dilepaskan dalam jangka waktu setelah fungsi kembali. Misalnya, sebuah fungsi memiliki kode sebagai berikut:

    Type tt ,result ; //生成两个栈对象
    
    tt = fun(tt); //函数返回时,生成的是一个临时对象object_copy2
    

    Implementasi dari pernyataan kedua di atas adalah sebagai berikut: pertama, fungsi fun yang dikembalikan akan menghasilkan sebuah obyek sementara object_copy2 dan kemudian akan memanggil operator pemberian nilai untuk mengeksekusi

    tt = object_copy2 ; //调用赋值运算符
    

    Apakah Anda melihat? Kompiler menghasilkan begitu banyak obyek sementara untuk kita tanpa kita sadari, dan pengeluaran waktu dan ruang untuk menghasilkan obyek sementara ini mungkin sangat besar, jadi, Anda mungkin mengerti mengapa untuk obyek brick-and-mortar adalah lebih baik untuk menggunakan konstan rujukan yang disampaikan daripada nilai yang disampaikan untuk parameter fungsi.

    Selanjutnya, perhatikan stack. Stack, juga dikenal sebagai Free Storage Area, yang didistribusikan secara dinamis selama proses eksekusi program, sehingga karakteristik utamanya adalah dinamis. Dalam C++, semua objek stack harus dibuat dan dihancurkan oleh programmer, sehingga jika tidak ditangani dengan baik, akan terjadi masalah memori. Jika Anda mendistribusikan objek stack, tetapi lupa untuk melepaskannya, akan terjadi kebocoran memori; dan jika Anda telah melepaskannya, tetapi tidak menetapkan pointernya ke NULL, pointer tersebut disebut sebagai penunjuk gantung, dan penggunaan pointer ini lagi akan menyebabkan akses ilegal, yang pada kasus yang serius dapat menyebabkan program crash.

    Jadi, bagaimana cara mendistribusikan objek heap dalam C++? Satu-satunya cara adalah dengan menggunakan new ((tentu saja, perintah malloc juga dapat digunakan untuk mendapatkan memori heap C), hanya dengan menggunakan new, sebuah bagian memori akan didistribusikan ke dalam heap dan akan dikembalikan pointer yang mengarah ke objek heap tersebut.

    Jika kita melihat kembali ke static storage area, maka semua static object, global object, dibagikan di static storage area. Untuk global object, ia dibagikan sebelum main () fungsi dieksekusi. Sebenarnya, sebelum main () fungsi dieksekusi, ia akan memanggil sebuah _main () fungsi yang dihasilkan oleh compiler, sedangkan _main () fungsi akan melakukan konstruksi dan inisialisasi dari semua global object, dan sebelum main () fungsi selesai, ia akan memanggil fungsi exit yang dihasilkan oleh compiler, untuk melepaskan semua global object.

    void main(void)
    {
        ... // 显式代码
    }
    
    
    // 实际上转化为这样:
    
    
    void main(void)
    {
        _main(); //隐式代码,由编译器产生,用以构造所有全局对象
        ...      // 显式代码
        ...
        exit() ; // 隐式代码,由编译器产生,用以释放所有全局对象
    }
    

    Jadi, setelah mengetahui hal ini, kita dapat memunculkan beberapa trik, misalnya, jika kita ingin melakukan beberapa persiapan sebelum main () dijalankan, maka kita dapat menulis persiapan tersebut ke dalam fungsi konstruksi dari objek global yang disesuaikan, sehingga sebelum kode eksplisit dari fungsi main () dijalankan, fungsi konstruksi dari objek global ini akan dipanggil dan melakukan tindakan yang diharapkan, sehingga kita mencapai tujuan kita. Jika kita berbicara tentang objek global di ruang penyimpanan statis, maka, apakah ada objek statis lokal?

    Ada juga objek statis, yaitu sebagai anggota statis dari sebuah kelas. Pertimbangan ini melibatkan beberapa masalah yang lebih rumit.

    Masalah pertama adalah umur objek anggota statis dari kelas, yang muncul seiring dengan munculnya objek kelas pertama, dan hilang pada akhir seluruh program. Yaitu, ada situasi di mana kita mendefinisikan sebuah kelas dalam program yang memiliki objek statis sebagai anggotanya, tetapi dalam proses eksekusi program, jika kita tidak membuat objek apa pun dari kelas tersebut, maka tidak akan ada objek statis yang terkandung dalam kelas tersebut.

    Masalah kedua adalah ketika:

    class Base
    {
    public:
        static Type s_object ;
    }
    
    
    class Derived1 : public Base / / 公共继承
    {
    
    
        ... // other data 
    
    
    }
    
    
    class Derived2 : public Base / / 公共继承
    {
    
    
        ... // other data 
    
    
    }
    
    
    Base example ;
    
    
    Derivde1 example1 ;
    
    
    Derivde2 example2 ;
    
    
    example.s_object = …… ;
    
    
    example1.s_object = …… ; 
    
    
    example2.s_object = …… ; 
    

    Perhatikan tiga pernyataan di atas yang ditandai sebagai blackbody, apakah s_object yang mereka kunjungi adalah objek yang sama? Jawabannya adalah ya, mereka memang menunjuk ke objek yang sama, dan itu tidak terdengar seperti benar, kan? Tapi itu adalah kenyataan, Anda dapat menuliskan sendiri bagian kode sederhana untuk memverifikasi.

    Mari kita berpikir, ketika kita memberikan sebuah obyek dari tipe Derived1 ke sebuah fungsi yang menerima argumen dari tipe Base non-referensi, maka akan terjadi pemotongan, lalu bagaimana pemotongan itu terjadi? Percayalah sekarang Anda sudah tahu, itu hanya mengambil subobject dari obyek dari tipe Derived1 dan mengabaikan semua anggota data lain yang disesuaikan oleh Derived1, lalu menyerahkan subobject ini ke fungsi (yang sebenarnya digunakan dalam fungsi adalah salinan dari subobject ini).

    Semua obyek derivatif dari jenis Base memiliki subobjek dari tipe Base (yang dapat ditunjuk ke obyek Derived1 dengan pointer tipe Base, yang juga merupakan kunci multi-modal), dan semua subobjek dan semua obyek dari tipe Base memiliki satu obyek s_object yang sama, dan tentu saja, setiap contoh dari seluruh kelas sistem warisan yang berasal dari tipe Base memiliki satu obyek s_object yang sama. Layout obyek dari contoh, contoh1, contoh2 yang disebutkan di atas adalah sebagai berikut:

  • 2 Perbandingan tiga jenis objek memori

    Keuntungan dari obyek bergelombang adalah dibuat secara otomatis pada saat yang tepat dan dihancurkan secara otomatis pada saat yang tepat, tanpa perlu perhatian pemrogram; dan penciptaan obyek bergelombang umumnya lebih cepat daripada obyek tumpukan, karena saat mendistribusikan obyek tumpukan, akan memanggil operasi operator new, operator new akan menggunakan semacam algoritma pencarian ruang memori, dan proses pencarian ini mungkin memakan waktu, menghasilkan obyek bergelombang tidak terlalu banyak masalah, hanya perlu menggerakkan penunjuk puncak bergelombang. Namun perlu dicatat bahwa biasanya kapasitas ruang bergelombang lebih kecil, biasanya 1MB bergelombang 2MB, sehingga obyek yang lebih besar tidak cocok untuk didistribusikan dalam bergelombang.

    Objek heap, yang dibuat dan dimusnahkan pada saat tertentu, harus ditentukan oleh programmer, yaitu, programmer memiliki kendali penuh atas kehidupan objek heap. Kita sering membutuhkan objek seperti itu, misalnya, kita perlu membuat objek yang dapat diakses oleh beberapa fungsi, tetapi tidak ingin membuatnya global, maka saat ini membuat objek heap adalah pilihan yang baik, dan kemudian memindahkan pointer objek heap ini di antara masing-masing fungsi, untuk mencapai berbagi objek tersebut. Selain itu, dibandingkan dengan ruang kosong, kapasitas heap jauh lebih besar.

    Selanjutnya, perhatikan objek statis.

    Pertama adalah obyek global. Obyek global menyediakan cara yang paling sederhana untuk komunikasi antar kelas dan komunikasi antar fungsi, meskipun cara ini tidak elegan. Secara umum, dalam bahasa yang sepenuhnya berorientasi objek, tidak ada obyek global, seperti C #, karena obyek global berarti tidak aman dan tinggi-coupled, menggunakan terlalu banyak obyek global dalam program akan sangat mengurangi program yang kuat, stabil, maintainability dan fleksibilitas.

    Kedua adalah anggota statis dari sebuah kelas, yang telah disebutkan di atas bahwa semua objek dari kelas induk dan derivatifnya berbagi objek anggota statis ini, sehingga anggota statis seperti itu pasti merupakan pilihan yang baik ketika perlu berbagi data atau berkomunikasi antara kelas atau antara objek kelas.

    Selanjutnya adalah objek lokal statis, yang terutama dapat digunakan untuk menyimpan objek tersebut dalam keadaan intermediate selama fungsi yang dipanggil berulang kali, salah satu contoh yang paling menonjol adalah fungsi rekursif, kita semua tahu bahwa fungsi rekursif adalah fungsi yang memanggil dirinya sendiri, jika dalam fungsi rekursif didefinisikan sebuah objek lokal nonstatic, maka ketika jumlah pengulangan cukup besar, maka pengeluaran yang dihasilkan juga sangat besar. Ini karena objek lokal nonstatic adalah objek siluman, setiap panggilan rekursif, akan menghasilkan objek seperti itu, setiap kali kembali, akan melepaskan objek ini, dan, seperti objek yang hanya terbatas pada lapisan panggilan saat ini, untuk lapisan yang lebih dalam dari embed dan lebih dangkal, tidak terlihat.

    Dalam desain fungsi rekursi, objek statis dapat digunakan sebagai pengganti objek lokal nonstatis, yang tidak hanya dapat mengurangi biaya yang dihasilkan dan dilepaskan oleh objek nonstatis setiap kali panggilan rekursi dan pengembalian, tetapi objek statis juga dapat menyimpan keadaan intermediate dari panggilan rekursi dan dapat diakses oleh setiap lapisan panggilan.

  • 3 Hasil tak terduga dari penggunaan pupuk

    Seperti yang telah dijelaskan di atas, sebuah object yang di-scan dibuat pada waktu yang tepat dan kemudian dilepaskan secara otomatis pada waktu yang tepat, yang berarti bahwa object yang di-scan memiliki fungsi pengelolaan otomatis. Jadi, di mana objek yang di-scan dilepaskan secara otomatis? Pertama, pada akhir masa hidupnya; kedua, pada saat fungsi yang di-scan tersebut mengalami ketidaknormalan. Anda mungkin berkata, semua ini normal, tidak ada yang salah. Ya, tidak ada yang salah.

    Jika kita membungkus sumber daya di dalam sebuah obyek, dan melakukan tindakan untuk membebaskan sumber daya dalam fungsi pembungkusan obyek tersebut, maka akan sangat mengurangi kemungkinan kebocoran sumber daya, karena obyek tersebut dapat secara otomatis membebaskan sumber daya, bahkan jika ada abnormalitas pada fungsi yang dimilikinya. Proses yang sebenarnya adalah sebagai berikut: ketika fungsi melepaskan abnormalitas, apa yang disebut stack_unwinding akan terjadi, yaitu, stack akan terbuka, karena obyek tersebut berada di dalam stack alami, sehingga dalam proses pemutaran kembali stack, fungsi pembungkusan obyek tersebut akan dijalankan, sehingga membebaskan sumber daya yang terbungkus.

  • 4 Dilarang membuat objek tumpukan

    Seperti yang telah disebutkan di atas, jika Anda memutuskan untuk melarang pembuatan jenis objek heap tertentu, maka Anda dapat membuat kelas kemasan sumber daya sendiri yang hanya dapat dibuat di dalam heap, sehingga akan secara otomatis melepaskan sumber daya yang dikemas dalam keadaan yang tidak normal.

    Jadi bagaimana kita bisa melarang pembuatan objek tumpukan? Kita sudah tahu bahwa satu-satunya cara untuk menghasilkan objek tumpukan adalah dengan menggunakan operasi new, dan jika kita melarang penggunaan new tidak akan berhasil. Lebih jauh lagi, operasi new akan memanggil operator new, dan operator new dapat dimuat ulang.

    #include <stdlib.h> //需要用到C式内存分配函数
    
    
    class Resource ; //代表需要被封装的资源类
    
    
    class NoHashObject
    {
    private: 
        Resource* ptr ;//指向被封装的资源
    
    
        ... ... //其它数据成员
    
    
        void* operator new(size_t size) //非严格实现,仅作示意之用
        { 
            return malloc(size) ; 
        } 
    
    
        void operator delete(void* pp) //非严格实现,仅作示意之用
        { 
            free(pp) ; 
        } 
    
    
    public: 
        NoHashObject() 
        { 
            //此处可以获得需要封装的资源,并让ptr指针指向该资源
    
    
            ptr = new Resource() ; 
        } 
    
    
        ~NoHashObject() 
        { 
    
    
            delete ptr ; //释放封装的资源
        } 
    }; 
    

    NoHashObject sekarang adalah kelas yang melarang objek tumpukan, jika Anda menulis kode berikut:

    NoHashObject* fp = new NoHashObject() ; // Kesalahan kompilasi!

    delete fp ;

    Kode di atas akan menghasilkan kesalahan kompilasi. Baiklah, sekarang Anda sudah tahu bagaimana merancang sebuah kelas yang melarang objek-objek heap, Anda mungkin memiliki pertanyaan seperti saya, apakah tidak mungkin untuk menghasilkan jenis objek heap jika definisi kelas NoHashObject tidak dapat diubah? Tidak, masih ada cara, saya menyebutnya sebagai cara untuk meretas kekerasan heap.

    void main(void)
    {
        char* temp = new char[sizeof(NoHashObject)] ; 
    
    
        //强制类型转换,现在ptr是一个指向NoHashObject对象的指针
    
    
        NoHashObject* obj_ptr = (NoHashObject*)temp ; 
    
    
        temp = NULL ; //防止通过temp指针修改NoHashObject对象
    
    
        //再一次强制类型转换,让rp指针指向堆中NoHashObject对象的ptr成员
    
    
        Resource* rp = (Resource*)obj_ptr ; 
    
    
        //初始化obj_ptr指向的NoHashObject对象的ptr成员
    
    
        rp = new Resource() ; 
    
    
        //现在可以通过使用obj_ptr指针使用堆中的NoHashObject对象成员了
    
    
        ... ... 
    
    
        delete rp ;//释放资源
    
    
        temp = (char*)obj_ptr ; 
    
    
        obj_ptr = NULL ;//防止悬挂指针产生
    
    
        delete [] temp ;//释放NoHashObject对象所占的堆空间。
    
    
        } 
    

    Implementasi di atas adalah bermasalah, dan implementasi ini hampir tidak digunakan dalam praktek, tetapi saya tetap menulis jalan keluar, karena memahaminya, bagi kita untuk memahami C++ memori objek yang baik. Untuk begitu banyak jenis paksa di atas konversi, apa yang paling mendasarnya? Kita bisa memahami sebagai berikut:

    Data dalam satu blok memori tidak berubah, dan jenisnya adalah kacamata yang kita kenakan. Ketika kita mengenakan kacamata, kita akan menggunakan tipe yang sesuai untuk menafsirkan data dalam memori, sehingga interpretasi yang berbeda akan mendapatkan informasi yang berbeda.

    Apa yang disebut dengan konversi tipe paksa sebenarnya adalah mengganti lensa dan melihat data yang sama di dalam memori.

    Perlu juga diingat bahwa komposisi data anggota objek mungkin berbeda dalam berbagai kompilasi, misalnya, kebanyakan kompilator menempatkan anggota pointer ptr NoHashObject di 4 byte pertama ruang objek, yang akan memastikan bahwa tindakan transformasi dari kalimat berikut dilakukan seperti yang kita harapkan:

    Resource* rp = (Resource*)obj_ptr ;

    Namun, tidak semua compiler seperti itu.

    Jika kita bisa melarang pembuatan objek-objek heap dari jenis tertentu, apakah kita bisa membuat sebuah kelas yang tidak dapat menghasilkan objek heap? Tentu saja bisa.

  • 5 Larangan untuk membuat objek yang berkilau

    Seperti yang telah disebutkan sebelumnya, ketika membuat objek frame, penunjuk penutup akan bergerak untuk mengambil ruang yang sesuai dengan ukuran frame, kemudian memanggil fungsi konstruktor yang sesuai secara langsung di ruang ini untuk membentuk objek frame, dan ketika fungsi kembali, akan memanggil fungsi analisisnya untuk membebaskan objek ini, dan kemudian menyesuaikan penunjuk penutup untuk mengambil kembali blok frame tersebut. Memori dalam proses ini tidak memerlukan operasi new/delete, jadi pengaturan operator new/delete sebagai pribadi tidak dapat mencapai tujuan. Tentu saja dari penjelasan di atas, Anda mungkin telah berpikir: membuat fungsi komposisi atau fungsi komposisi sebagai pribadi, sehingga sistem tidak dapat memanggil fungsi komposisi / komposisi, tentu saja tidak dapat menghasilkan objek dalam frame.

    Ini benar-benar bisa dilakukan, dan saya juga berencana untuk melakukan ini. Tapi sebelum itu, ada satu hal yang perlu dipertimbangkan, yaitu, jika kita membuat fungsi konstruksi menjadi pribadi, maka kita tidak dapat menggunakan new untuk menghasilkan objek heap secara langsung, karena new akan memanggil fungsi konstruksi setelah memberikan ruang untuk objek. Jadi, saya hanya berencana untuk membuat fungsi komposisi sebagai pribadi.

    Jika sebuah kelas tidak dimaksudkan untuk menjadi kelas dasar, biasanya yang dilakukan adalah mendeklarasikan fungsi desentralisasi sebagai private.

    Untuk membatasi obyek yang dikorupsi, tetapi tidak membatasi warisan, kita dapat menyatakan fungsi desentralisasi sebagai protected, sehingga keduanya baik. Seperti yang ditunjukkan oleh kode berikut:

    class NoStackObject
    {
    protected: 
    
    
        ~NoStackObject() { } 
    
    
    public: 
    
    
        void destroy() 
    
    
        { 
    
    
            delete this ;//调用保护析构函数
    
    
        } 
    }; 
    

    Selanjutnya, kita bisa menggunakan kelas NoStackObject seperti ini:

    NoStackObject* hash_ptr = new NoStackObject() ;

    … … // melakukan operasi pada objek yang diarahkan oleh hash_ptr

    hash_ptr->destroy() ; Nah, apakah itu agak aneh, kita membuat sebuah objek dengan new, tetapi bukan dengan delete untuk menghapusnya, tapi dengan destroying. Jelas, pengguna tidak terbiasa dengan penggunaan yang aneh ini. Jadi, saya memutuskan untuk membuat fungsi konstruksi sebagai pribadi atau dilindungi. Ini kembali ke pertanyaan yang telah saya coba hindari di atas, yaitu tidak menggunakan new, lalu bagaimana cara membuat objek?

    class NoStackObject
    {
    protected: 
    
    
        NoStackObject() { } 
    
    
        ~NoStackObject() { } 
    
    
    public: 
    
    
        static NoStackObject* creatInstance() 
        { 
            return new NoStackObject() ;//调用保护的构造函数
        } 
    
    
        void destroy() 
        { 
    
    
            delete this ;//调用保护的析构函数
    
    
        } 
    };
    

    Sekarang kita bisa menggunakan NoStackObject dengan cara ini:

    NoStackObject* hash_ptr = NoStackObject::creatInstance() ;

    … … // melakukan operasi pada objek yang diarahkan oleh hash_ptr

    hash_ptr->destroy() ;

    hash_ptr = NULL ; // mencegah penggunaan penunjuk gantung

    Sekarang saya merasa lebih baik, karena saya bisa membuat dan melepaskan objek dengan cara yang sama.

  • Metode Pengembalian Sampah di C++

Banyak programmer C atau C++ yang tidak setuju dengan pengembalian sampah karena menganggap bahwa pengembalian sampah pasti lebih tidak efisien daripada mengelola memori dinamis sendiri, dan bahwa pengembalian sampah pasti akan membuat program berhenti di sana, sedangkan jika Anda mengendalikan pengelolaan memori, alokasi dan waktu pelepasan stabil dan tidak akan menyebabkan program berhenti. Akhirnya, banyak programmer C/C++ yang yakin bahwa tidak ada mekanisme pengembalian sampah yang dapat diterapkan di C/C++.

Faktanya, mekanisme pemulihan sampah tidak lambat, bahkan lebih efisien daripada alokasi memori dinamis. Karena kita hanya dapat mendistribusikan tanpa membebaskan, maka alokasi memori hanya perlu mendapatkan memori baru dari tumpukan terus menerus, pengarah tumpukan bergerak sudah cukup; dan proses pelepasan diabaikan, dan secara alami juga mempercepat kecepatan. Algoritma pemulihan sampah modern telah berkembang banyak, algoritma pengumpulan tambahan telah memungkinkan proses pemulihan sampah dilakukan secara bertahap, menghindari gangguan program.

Algoritma untuk memulihkan sampah biasanya didasarkan pada memindai dan menandai semua blok memori yang mungkin digunakan saat ini, memulihkan memori yang tidak ditandai dari semua memori yang telah dialokasikan. Pandangan bahwa tidak mungkin untuk memulihkan sampah dalam C / C ++ biasanya didasarkan pada ketidakmampuan untuk memindai dengan benar semua blok memori yang mungkin masih digunakan, tetapi apa yang tampaknya mustahil sebenarnya tidak rumit. Pertama, dengan memindai data dari memori, pointer yang dialokasikan secara dinamis ke stack memori mudah diidentifikasi, dan jika ada kesalahan pengidentifikasian, hanya beberapa pointer yang tidak dialokasikan dapat dialokasikan, dan tidak ada pointer yang tidak dialokasikan.

Pada saat pengembalian sampah, hanya perlu memindai segmen bss, segmen data, dan ruang frame yang sedang digunakan saat ini, untuk menemukan jumlah yang mungkin merupakan pointer memori dinamis, memindai memori referensi secara berulang dapat memperoleh semua memori dinamis yang sedang digunakan saat ini.

Jika Anda ingin mengimplementasikan pengisi ulang sampah yang bagus untuk proyek Anda, Anda dapat meningkatkan kecepatan manajemen memori, atau bahkan mengurangi konsumsi memori secara keseluruhan. Jika Anda tertarik, Anda dapat mencari artikel dan perpustakaan yang ada di internet tentang pengembalian sampah, yang sangat penting bagi seorang pemrogram untuk mengembangkan wawasan.

Dikutip dari:HK Zhang

  • #### Bagaimana mungkin sebuah pointer yang diberi alamat variabel lokal dapat bertahan hidup sampai prosesnya selesai?
  #include<stdio.h>
  int*fun(){
      int k = 12;
      return &k;
  }
  int main(){
      int *p = fun();    
      printf("%d\n", *p);

      getchar();
      return 0;
  }

Tidak hanya dapat diakses, tetapi juga dimodifikasi, hanya saja akses tersebut tidak pasti. Alamat variabel lokal berada dalam stack program sendiri, setelah variabel otoritas berakhir, nilainya tetap ada asalkan tidak memberikan alamat memori variabel lokal tersebut kepada variabel lain. Tetapi jika diubah, itu lebih berbahaya, karena alamat memori ini mungkin memberi program variabel lain, dan jika diubah secara paksa melalui pointer, mungkin menyebabkan program crash

csdn bbs