Windowsのスタックメモリの申請と解放について
著作権所有、転載は出典を明記してください、ありがとうございます!http://blog.csdn.net/walkinginthewind/article/details/7069176
C言語でメモリを動的に申請するにはmalloc関数を呼び出し、動的メモリを解放するにはfree関数を呼び出す必要があることはよく知られています.メモリの申請と解放はいずれもスタック(Heap)上で行われている.もちろん、メモリとは、仮想メモリです.C言語のmallocとfreeは、windowsでは主にHeapAllocとHeapFreeによって実現される.
各プロセスは初期化時にRtlProcessHeap()関数を呼び出してプロセスのヒープメモリを管理するHEAPオブジェクトを構築します.
mallocを使用してメモリを申請する場合は、サイズを指定しますが、freeを使用して解放する場合は、解放するメモリの開始アドレスを指定するだけです.
次のようになります.
int * p = (int*)malloc(100 * sizeof(int));//100個のintサイズのメモリを申請する
...//その他の操作
free(p);//pが指すメモリを解放する
では、システムが特定のポインタが指すダイナミックメモリのサイズをどのように知ったり記録したりしているのか、疑問に思うに違いありません.
Windowsの実装案は簡単で、各ダイナミックメモリの上部にそのメモリの大きさなどの関連情報を保存することです.これは、スタックメモリを使用すると、追加のシステムオーバーヘッドが発生し、Windowsでは次の構造体を通じて関連情報を保存することを示しています.
(WRKの定義は、XPとwin 7の下でテストされ、win 2000のソースコードの定義はこれとは異なります)
freeがメモリを解放するときはその構造体の情報に依存するため、mallocが返さないアドレスや解放されたアドレスでは、その構造の内容は一般的に正しくありません.これはfreeがエラーする原因です.
次のようになります.
int * p = (int*)malloc(100 * sizeof(int));//100個のintサイズのメモリを申請する
...//その他の操作
free(p);//pが指すメモリを解放する
free(p);//リリースしたメモリを再解放すると、RTL_のためエラーが発生します.HEAP_ENTRYはもう有効ではありません.
したがって、ポインタが指すダイナミックメモリを解放した後、freeの値がNULLのアドレスでエラーがないため、ポインタをNULLに割り当てたほうがいいです.
次のようになります.
int * p = (int*)malloc(100 * sizeof(int));//100個のintサイズのメモリを申請する
...//その他の操作
//例えばメモリの一部を解放したい
int * q = p + 20;
free(q);//qが指すメモリを解放すると、アドレスqが対応するRTL_HEAP_ENTRY構造体情報は無効です
したがってfreeはmallocが返す有効なアドレスしか解放できません.
次のプログラムで検証します.
出力結果は,i:0,size:0 i:1,size:1 i:2,size:2...i:999,size:999まとめ:windowsソースコードに基づいて,Cライブラリ関数freeの実装におけるメモリサイズ情報の記録方法を簡単に解析した.
C言語でメモリを動的に申請するにはmalloc関数を呼び出し、動的メモリを解放するにはfree関数を呼び出す必要があることはよく知られています.メモリの申請と解放はいずれもスタック(Heap)上で行われている.もちろん、メモリとは、仮想メモリです.C言語のmallocとfreeは、windowsでは主にHeapAllocとHeapFreeによって実現される.
各プロセスは初期化時にRtlProcessHeap()関数を呼び出してプロセスのヒープメモリを管理するHEAPオブジェクトを構築します.
mallocを使用してメモリを申請する場合は、サイズを指定しますが、freeを使用して解放する場合は、解放するメモリの開始アドレスを指定するだけです.
次のようになります.
int * p = (int*)malloc(100 * sizeof(int));//100個のintサイズのメモリを申請する
...//その他の操作
free(p);//pが指すメモリを解放する
では、システムが特定のポインタが指すダイナミックメモリのサイズをどのように知ったり記録したりしているのか、疑問に思うに違いありません.
Windowsの実装案は簡単で、各ダイナミックメモリの上部にそのメモリの大きさなどの関連情報を保存することです.これは、スタックメモリを使用すると、追加のシステムオーバーヘッドが発生し、Windowsでは次の構造体を通じて関連情報を保存することを示しています.
(WRKの定義は、XPとwin 7の下でテストされ、win 2000のソースコードの定義はこれとは異なります)
typedef struct _RTL_HEAP_ENTRY {
SIZE_T Size; //
USHORT Flags;
USHORT AllocatorBackTraceIndex;
union {
struct {
SIZE_T Settable;
ULONG Tag;
} s1; // All other heap entries
struct {
SIZE_T CommittedSize;
PVOID FirstBlock;
} s2; // RTL_SEGMENT
} u;
} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;
freeがメモリを解放するときはその構造体の情報に依存するため、mallocが返さないアドレスや解放されたアドレスでは、その構造の内容は一般的に正しくありません.これはfreeがエラーする原因です.
次のようになります.
int * p = (int*)malloc(100 * sizeof(int));//100個のintサイズのメモリを申請する
...//その他の操作
free(p);//pが指すメモリを解放する
free(p);//リリースしたメモリを再解放すると、RTL_のためエラーが発生します.HEAP_ENTRYはもう有効ではありません.
したがって、ポインタが指すダイナミックメモリを解放した後、freeの値がNULLのアドレスでエラーがないため、ポインタをNULLに割り当てたほうがいいです.
次のようになります.
int * p = (int*)malloc(100 * sizeof(int));//100個のintサイズのメモリを申請する
...//その他の操作
//例えばメモリの一部を解放したい
int * q = p + 20;
free(q);//qが指すメモリを解放すると、アドレスqが対応するRTL_HEAP_ENTRY構造体情報は無効です
したがってfreeはmallocが返す有効なアドレスしか解放できません.
次のプログラムで検証します.
#include<stdio.h>
#include<windows.h>
typedef struct _RTL_HEAP_ENTRY {
SIZE_T Size;
USHORT Flags;
USHORT AllocatorBackTraceIndex;
union {
struct {
SIZE_T Settable;
ULONG Tag;
} s1;
struct {
SIZE_T CommittedSize;
PVOID FirstBlock;
} s2;
} u;
} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;
int main()
{
PRTL_HEAP_ENTRY pHeapEntry;
int *p;
for(int i = 0; i < 1000; i++)
{
p=(int*)malloc(i);
pHeapEntry=(PRTL_HEAP_ENTRY(p)-1);
printf("i: %d, size: %d
", i, pHeapEntry->Size);
free(p);
}
return 0;
}
出力結果は,i:0,size:0 i:1,size:1 i:2,size:2...i:999,size:999まとめ:windowsソースコードに基づいて,Cライブラリ関数freeの実装におけるメモリサイズ情報の記録方法を簡単に解析した.