C++ベース——メモリ管理編


メモリ管理はコンピュータプログラミングの最も基本的な分野の一つである.多くのスクリプト言語では、メモリがどのように管理されているかを心配する必要はありません.これにより、メモリ管理の重要性が少し低下するわけではありません.実際のプログラミングでは、メモリマネージャの能力と限界を理解することが重要です.ほとんどのシステム言語では、CやC++など、メモリ管理が必要です.本稿では、手動、半手動、および自動メモリ管理の実践の基本概念について説明します.IBMメモリ管理の紹介
関連する内容は次のとおりです.
  • C API malloc free,malloc(ディスペンサがメモリ割り当てを実行するプロセス)
  • メモリの回収(GCメカニズム)
  • C++インテリジェントポインタで実現されたオブジェクトスタックメモリ解放回収スタックメモリ
  • メモリリーク判定と
  • 防止
  • 半自動メモリ管理リファレンスカウント
  • メモリプール(pool)STLメモリプール
  • を実現
    メモリプールの目的
  • new式でオブジェクトを動的に割り当てるとoperator newが呼び出されてメモリ割り当てが行われます.このステップはオペレーティングシステムと直接関連しています.オペレーティングシステムは、空きメモリを指すポインタをユーザーに返すために比較的煩雑なプロセスを経なければならない場合があります.これもnewの比較的時間がかかる部分です.2つ目のステップは、コンストラクション関数を使用して初期化することです.メモリ割り当てに時間がかかる以上、一度に大きなメモリを割り当てて、ユーザーが必要とするときにその一部をユーザーに割り当てることが考えられます.そうすると、一度に割り当てて、何度も使用すると、自然に効率が向上し、大きなメモリを管理するためのメモリ構造、つまり今日お話しするメモリプールです.
  • メモリプールがもたらすもう一つの利点は、newを頻繁に使用するとシステムメモリ空間の断片化が深刻になり、結果として連続した大きなメモリを見つけることが難しく、空間利用率が低く、メモリプールが一度に大きなメモリ空間を割り当てることで、メモリ断片化の問題を緩和することです.

  • 第1レベルのコンフィギュレータ
    第1段コンフィギュレータは、malloc()、free()、realloc()などのC関数で実際のメモリ構成、解放、再構成などの操作を実行し、メモリ要件が満たされない場合に指定した関数を呼び出すことができます.
    セカンダルコンフィギュレータ
    第2レベルのコンフィギュレータは16個の空きチェーンテーブルを維持しています(free list)は、それぞれの管理サイズが8、16、24、32、40、48、56、64、72、80、88、96、104、112、120、128 bytesの小さなメモリブロックである.割り当てるメモリが128 bytesより大きい場合は、第1レベルのコンフィギュレータ処理に移行し、mallocを直接使用する.割り当てるメモリが128 bytesより小さい場合は、メモリプールで管理する(memory pool)は、2段目のコンフィギュレーションを使用して、適切な空きチェーンテーブルを探し出し、その上から1つのノードを外してそのヘッダポインタをユーザーに返すことで、ユーザーに対するメモリの割り当てが完了する.解放プロセスはちょうど割り当てに対応し、ユーザーが割り当てたメモリが128 bytesより大きい場合はfreeを直接使用し、そうでない場合は適切な空きチェーンテーブルを探し出し、ポインタが指すこのセグメントのメモリを空きチェーンテーブルに再接続します(メモリをオペレーティングシステムに返さないので、再利用できます).
    小さいメモリブロック(空きチェーンテーブル管理)->大きいメモリブロック(mallocからOSに申請)
    プロセスの概要
    allocateリクエストsizeサイズのメモリ領域を使用し、リクエストするメモリサイズが128 bytesより大きい場合はmallocを直接使用します.必要なメモリサイズが128 bytes未満の場合、allocateはsizeに基づいて最適な空きチェーンテーブルを見つける.a.チェーンテーブルが空でない場合は、最初のメモリブロックを返し、チェーンテーブルヘッダを2番目のメモリブロックに変更します.b.チェーンテーブルが空の場合は、refillを使用して空きチェーンテーブルに新しいスペースを埋めます.x.メモリプールに1つ以上のメモリブロックがある場合は、できるだけ多くのメモリブロック(ただし最大20個)を割り当て、1つのメモリブロックを返し、他のメモリブロックをチェーンテーブルに追加します.y.メモリプールにメモリブロックが1つしかない場合は、直接ユーザに返す.z.メモリプールにメモリブロックが1つもない場合は、再びオペレーティングシステムにメモリの割り当てを要求する.Iシステムメモリは十分で、分配に成功し、再びbプロセスIIの分配に失敗し、各空きチェーンテーブルを循環し、空間A.を探し、再びプロセスb B.を行い、空間が見つからず、異常なユーザー呼び出しdeallocateを投げ出してメモリ空間を解放し、もし解放するメモリ空間が128 bytesより大きい場合、freeを直接呼び出す.そうでない場合は、サイズに応じて適切な空きチェーンテーブルを見つけ、挿入します.特徴はこうです
    メモリプールの初期化を開始したばかりの頃、メモリプールにはメモリがなく、すべての空きチェーンテーブルが空のチェーンテーブルであった.ユーザがメモリプールにメモリを最初に要求した場合にのみ、メモリプールは上記の手順の1->2->b->zを順次実行してメモリプールおよびチェーンテーブルの最初の充填を完了しますが、この場合、他の未使用チェーンテーブルは空です.
    新とMallocの違い
  • malloc

  • mallocのフルネームはmemory allocationで、中国語では動的メモリ割り当てと呼ばれています.プロトタイプ:extern void*malloc(unsigned int num_bytes);説明:割当長num_bytesバイトのメモリブロック.割り当てに成功すると、分類されたメモリへのポインタが返されます.割り当てに失敗すると、空のポインタNULLが返されます.(したがって、メモリの申請が完了したら、申請したメモリが空であるかどうかを判断する必要があります)メモリが使用されなくなった場合、free()関数を使用してメモリブロックの解放を説明します.戻りタイプ:voidタイプ、汎用変形タイプポインタ、c、c++の規定を表し、voidタイプは他のタイプのポインタに強制的に変換することができる.void*とは、メモリ領域を申請する際に、ユーザーがこの領域でどのようなタイプのデータを格納するか分からないことを意味します.リリース:void free(void*FirstByte);mallocが割り当てた空間はプログラムやオペレーティングシステムに返され、つまりこのメモリが解放されます.
    注意事項:1)メモリ領域を申請した後、割り当てに成功したかどうかを確認する必要があります.2)申請したメモリを再使用する必要がない場合は、解放してください.リリース後、このメモリを指すポインタをNULLに向け、後のプログラムがうっかり野ポインタ3)mallocとfreeをペアで使用しないようにしなければならない.リリースは1回しかリリースできません.2回以上リリースするとエラーが発生します.(空ポインタを解放例外、空ポインタを解放するのは何もしていないことに等しい.空ポインタを解放するのは何度も問題ない)4)mallocはスタックからメモリを取得する.関数が返すポインタはスタックの中のメモリを指す.オペレーティングシステムには空きメモリアドレスを記録するチェーンテーブルがあり、オペレーティングシステムがプログラムの申請を受け取るとチェーンテーブルを遍歴し、最初のメモリを探す空きノードチェーンテーブルから削除され、そのノードがプログラムに割り当てられます.
  • new

  • c++では、newとdeleteで配列または単一オブジェクトを動的に作成および解放します.オブジェクトを動的に作成する場合は、名前を付ける必要がなく、データ型を指定するだけです.delete pi;//個々のオブジェクトdelete[]pi;//を解放アレイの解放
  • 両者の区別1)newは、指定されたタイプのポインタを返し、必要なサイズを自動的に計算することができる.mallocは、バイト数を手動で計算し、返された後にタイプを実際のタイプに変換するポインタを強制する必要があります.(2)mallocはメモリを割り当てるだけでなく、得られたメモリを初期化することはできないので、得られた新しいメモリの中で、その値はランダムになる.newはメモリを割り当てるだけでなく、メモリの中のオブジェクトを初期化する.freeはメモリを解放するだけでなく、deleteはメモリを解放するだけでなく、オブジェクトの構造関数を呼び出し、オブジェクトを破棄する.(3)malloc/freeはc++/cの標準ライブラリ関数であり、ヘッダファイルはstdlib.hである.new/deleteはc++の演算子である.動的メモリの申請とメモリの解放に使用できる.(4)new/deleteはペアで使用する必要があり、mallocとfreeも同様に
  • である.
    新とmallocの微妙な違い
  • で申請されたメモリの場所newオペレータは、フリーストレージ領域から(free store)上はオブジェクトにメモリ空間を動的に割り当て、malloc関数はスタックからメモリを動的に割り当てる.フリーメモリ領域はC++newオペレータに基づく抽象概念であり、newオペレータによるメモリ申請であり、このメモリはフリーメモリ領域である.スタックはオペレーティングシステムにおける用語であり、オペレーティングシステムが維持する特殊なメモリであり、プログラムのメモリ動作に用いられるステータス割当て、C言語はmallocを使用してスタックからメモリを割り当て、freeを使用して割り当てられた対応するメモリを解放します.では、フリー・ストレージ領域がスタック(問題はnewがスタックにメモリを動的に割り当てることができるかどうかに等しい)であるかどうかは、operator newの実装の詳細に依存する.フリー・ストレージ領域は、スタックだけでなく、静的ストレージ領域であってもよい.operator newがどこでオブジェクトにメモリを割り当てるかによって決まる.特に、newはオブジェクトにメモリを割り当てなくてもよい!
  • 戻りタイプセキュリティnewオペレータメモリ割り当てに成功した場合、戻りはオブジェクトタイプのポインタであり、タイプはオブジェクトと厳格に一致し、タイプ変換を行う必要がないため、newはタイプセキュリティに合致するオペレータである.mallocメモリ割り当てに成功したのはvoid*を返し、強制タイプ変換によってvoid*ポインタを必要なタイプに変換する必要があります.タイプセキュリティはメモリセキュリティに大きく等価であり、タイプセキュリティのコードは、自分が許可されていないメモリ領域をメソッドしようとしません.C++のタイプのセキュリティについては、また多くのことが言えます.
  • メモリ割付失敗時の戻り値newメモリ割付失敗時にbac_が投げ出されるalloc異常、NULLは返されません.mallocメモリの割り当てに失敗した場合はNULLを返します.

  • インテリジェントポインタテンプレート
    template <typename T>
    class smart_ptrs {
         
    
    public:
        smart_ptrs(T*); //            
        smart_ptrs(smart_ptrs&);
    
        T* operator->(); //        
        T& operator*(); //         
        smart_ptrs& operator=(smart_ptrs&); //        
        
        ~smart_ptrs(); //       
    
    private:
        int *count; //    
        T *p; //           
    };
    
    template <typename T>
    smart_ptrs<T>::smart_ptrs(T *p): count(new int(1)), p(p) {
         
    }
    //     
    template <typename T>
     T* smart_ptrs<T>::operator->() {
         
        return p;
     }
     //    
     template <typename T>
    T& smart_ptrs<T>::operator*() {
         
        return *p;
    }
    //    
    template <typename T>
    smart_ptrs<T>::~smart_ptrs() {
         
        if (--*count == 0) {
         
            delete count;
            delete p;
        }
    }
    //     
    template <typename T>
    smart_ptrs<T>& smart_ptrs<T>::operator=(smart_ptrs& sp) {
         
        ++*sp.count;
        if (--*count == 0) {
          //           
            delete count;
            delete p;
        }
        this->p = sp.p;
        this->count = sp.count;
        return *this;
    }