mallocのほんの少し

3395 ワード

質問:mallocはスレッドが安全ですか?
質問:mallocはどのように実現しましたか? : , , malloc関数スレッドは安全ですが、再入力できません.malloc関数はユーザー空間で各プロセスが共有するメモリチェーンテーブルを自分で管理します.共有リソースアクセスがあるため、スレッドが安全ではありません.スレッドのセキュリティを確保するために、ロック保護を追加します.再帰ロックは、プログラムがmalloc関数を呼び出すと信号を受信し、信号処理関数でmalloc関数を呼び出すと、一般的なロックを使用するとデッドロック(信号処理関数が元のプログラムの実行を中断する)を引き起こす. 上記のシーンを押すと、再入力性が保証されず、プログラムがmalloc関数を呼び出すと信号を受信し、信号処理関数でmalloc関数を呼び出すと共有メモリチェーンテーブルなどのリソースmalloc関数がカーネルにアクセスする共有データ構造が正常にロック保護される.1つのプロセスがmalloc関数をカーネルに呼び出すと、信号処理関数を実行するには、ユーザースペースに戻るまで待たなければなりません.カーネルデータ構造へのアクセスが完了し、カーネルロックが解放されますので、問題はありません.
  malloc関数の本質は、使用可能なメモリブロックを長い空きチェーンテーブルのプロトタイプに接続することにある:extern void* malloc(unsigned int num_bytes);用法:#include/#include  malloc関数を呼び出すときに現れる.空きチェーンテーブルに沿って、ユーザー要求を満たすのに十分な大きさのメモリブロックを探し、そのメモリブロックを2つに分けます.1つのブロックのサイズはユーザー要求のサイズと等しく、もう1つのブロックのサイズは残りのバイトです.ユーザーに割り当てられたメモリをユーザーに渡し、残りは空きチェーンテーブルに戻ります.フリーを呼び出すと、解放されたメモリブロックが空きチェーンテーブルに接続されます.最後の最後に、空きチェーンテーブルは多くの小さなメモリにカットされますが、このとき大きなメモリテーブルを申請すると、空きチェーンテーブルにはユーザーの要求を満たすセグメントがない可能性があります.mallocは遅延を要求し、空きチェーンテーブルで各メモリセグメントをチェックし始め、整理合併を行い、パートナーアルゴリズムのように思います.
オペレーティングシステムでは、Unix環境の高度なプログラミング:多くの実装では、割り当てられたストレージスペースが要求されたものよりもやや大きくなり、追加のスペースは管理情報を記録するために使用されます.割り当てられたブロックの長さ、次の割り当ての速いポインタなどを指します.このお酒は、割り当てられた領域の末尾を書いた場合、後の管理情報が書き換えられることを意味します.このタイプのエラーは災難的であるが、このエラーはすぐには暴露されないため、割り当てブロックへのポインタを後方に移動しても、このブロックの管理情報mallocが書き換えられる可能性があることは発見しにくい.
struct mem_control_block
{
	int is_available;
	int size;
};

  malloc_Init初期化メモリ割り当てレイヤシーケンスの関数:割り当てプログラムを初期化済みとして識別し、システム内の最後の有効メモリアドレスを見つけ、管理するメモリへのポインタがマッピングされたメモリの境界(最後の有効アドレス)を確立し、システムブレークポイントまたは現在のブレークポイントと呼ばれることが多い.sbrk(0)パラメータに与えられたバイト数に基づいて現在のシステム割り込みポイントを移動し、新しいシステム割り込みポイントを返します.パラメータ0を使用して現在の割り込みポイントだけを返します.
void malloc_init()
{
	last_valid_address=sbrk(0);
	managed_memory_start=last_valid_address;
	has_initalized=1;
}

  mallocを呼び出すプログラムは、この構造を知る必要はありません.ポインタを返す前に、ポインタをこの構造に移動した後、それを隠して、戻ったポインタが他の使用に使用されていないメモリを指し、呼び出し者の観点から、空のメモリが得られます.freeを介してポインタを返す場合は、数バイト後退するだけでこの構造を再び見つけることができます.
void free(void*  firstbyte)
{
	struct mem_control_block* mcb;
	mcb=firstbyte-sizeof(struct men_control_block);
	mcb->is_available=1;
	return ;
}

 glibcは不定長のメモリブロックチェーンテーブルだけでなく、いくつかを維持しています.このチェーンテーブルはサイズ範囲を担当しています.この方法は、大きなメモリを割り当てる際の遍歴コストを効果的に削減します.glibcの別の戦略は、空きチェーンテーブルのメンテナンスを知らないことです.また、バッファチェーンテーブルとキャッシュチェーンテーブルを別途維持し、割り当てられたときにまずキャッシュで検索し、失敗した後にアイドルチェーンテーブルで検索し、見つかったメモリブロックが大きい場合は、切断後の残りのメモリブロックをキャッシュチェーンテーブルに挿入します.アイドルチェーンテーブルの検索に失敗した場合は、キャッシュチェーンテーブルに検索します.適切な空きブロックがない場合は、リクエスト数よりも良いメモリブロックをメモリに申請し、残りのメモリをチェーンテーブルに入れます.
Linuxは、スタックの開始アドレスからbreakまでのアドレス空間をマッピングしたbreakポインタを維持します.このポインタは、スタックの開始アドレスからbreakまでの間のアドレス空間をマッピングし、プロセスにアクセスできます.breakから上へはマッピングされていないアドレス空間です.この空間にアクセスすると、プログラムはプロセスの実際の使用可能なスタックサイズを増加させます.Linuxはbrkとsbrkシステムを通じてbreakポインタ    void* sbrk(intptr_t increment);  brkはbreakポインタを直接アドレスに設定し、sbrkはbreakがincrementで指定したインクリメンタルを現在の位置から移動します.brkは、実行に成功した場合に0を返します.そうでなければ、-1を返し、errnoをENOMENに設定します.sbrkが成功した場合、breakが移動する前に指すアドレスを返します.そうでなければ、(void*)-1  を返します.また、Linuxはページごとにメモリマッピングされているため、breakがページサイズで整列していないように設定されている場合、システムは実際には最後に完全なページをマッピングします.したがって、実際にマッピングされたメモリ空間は、breakが指す場所よりも大きいが、breakを使用した後のアドレスは危険であり、breakの後に使用可能なメモリアドレスが確かに小さなブロックある可能性がある.