なぜmallocは要求されたものとは異なるバイト数を割り当てるのですか?
質問
このコードを持っています
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
int main(){
void *a, *b;
a = malloc(16);
b = malloc(16);
printf("\n block size (for a): %p-%p : %li", b, a, b-a);
a = malloc(1024);
b = malloc(1024);
printf("\n block size (for a): %p-%p : %li", b, a, b-a);
}
これは、最後に割り当てられたブロックサイズ(16または1024)を印刷しませんか?代わりに24と1032を出力するため、割り当てられたメモリ量には8バイト余分にあるようです。
問題は(このテストケースを作成する前に)関数(1024バイト)でmalloc()
を実行し、割り当てられた結果を返すことです。関数の戻り値でブロックサイズをチェックすると、516ブロックを取得します...理由がわかりません。これが、割り当てられたバッファで何らかの処理を行った後に発生するメモリ破損の原因であると思われます:)
編集: どのように入手できますかCのポインタからの配列のサイズ?と同じことを尋ねているようです、再投稿して申し訳ありません。
例をより具体的なコードに再作成しました:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
short int * mallocStuff(long int number, short int base){
short int *array;
int size=1024;
array=(short int*)calloc(1,size);
//array=(short int*)malloc(size);
return array;
}
int main(){
short int **translatedArray;
translatedArray=malloc(4*sizeof(short int));
int i;
for(i=0;i<4;i++){
translatedArray[i]=mallocStuff(0,0);
if(i>0)
printf("\n block size (for a): %p-%p : %i",
translatedArray[i], translatedArray[i-1], translatedArray[i]-translatedArray[i-1]);
}
return 0;
}
そして出力は
block size (for a): 0x804a420-0x804a018 : 516
block size (for a): 0x804a828-0x804a420 : 516
block size (for a): 0x804ac30-0x804a828 : 516
1024より大きい上記の投稿によると、間違っていますか
解決
バグがあります。代わりに:
translatedArray=malloc(4*sizeof(short int));
あなたが持っている必要があります
translatedArray=malloc(4*sizeof(short int*));
コード内の欠落しているポインターに注意してください。これは、観察された動作の原因であると思われます。
0x804a420 - 0x804a018 = 1032
ではなく、516
にも注意してください。式translatedArray[i] - translatedArray[i - 1]
は、2つのアドレス間の要素(短い整数、または単純に短い)の数を提供し、バイトの数ではありません。
他のヒント
最初に、Mallocは2つの連続したmalloc呼び出しが連続したポインターを返すことを保証しません。
第二に、特定のアーキテクチャに応じて、異なるアライメント規則が適用されます。 1バイトを要求することもありますが、アーキテクチャは8バイトまたは4バイトの間隔での割り当てを好みます。
第三に、mallocは割り当てられたブロックの大きさなどを保存するためにいくらかのオーバーヘッドを必要とします。
ドキュメンテーションに書かれていることを超えてmallocが何をしているのかを推測しないでください!
malloc
関数は、簿記情報を保存するために、常に要求よりわずかに多くを割り当てます。結局、free()
を呼び出すときは、ブロックの大きさを知る必要があります。
また、一般的にshort int
実装は、要求されたサイズを次の8または16の倍数または他の丸められた数値に切り上げます。
更新:質問に対する本当の答えは、<=>タイプの使用にあります。型付きポインター間でポインター演算(減算)を行うと、CとC ++は、ポイントされたものの number の差を返します。サイズが2バイトの<=>を指しているため、返される値は予想の半分になります。
一方、<=>は、結果をどのようにキャストしても、常に指定された数のバイトを割り当てます。これを試してください:
array=(short int*)malloc(sizeof(short int) * size);
2つのmalloc呼び出しが正確にまとめられたブロックを返すという保証はありません-実際、結果がNULLでない場合、少なくとも1つと同じ大きさのブロックを指すことを除いて、結果に関する保証はまったくありません要求されました。
内部的には、ほとんどのmallocはヒープを管理するのに役立つ作業データを保持しています。たとえば、これらの8バイトには2つのポインターが含まれる場合があります。1つは次のブロックを指し、もう1つは前のブロックを指します。実行しているOSについて言及しなかったため、これらの8バイトが何であるかはわかりませんが、mallocが舞台裏でメモリを使用することは完全に普通です。
一部のアロケーター(Windowsなど)は、ポインターが与えられるとブロックサイズを検出するライブラリー機能を提供しますが、一部の機能はかなり難解な機能であるため、提供しません。
mallocが返すものは、mallocの実装とアーキテクチャによって異なります。他の人がすでに言っているように、要求されたメモリの量、またはNULLを少なくとも取得することが保証されています。これは、配列の末尾を超えて書き込むことができ、セグメンテーションフォールトを取得できない場合もあるためです。それは、あなたが実際にこのメモリに有効なアクセス権を持っているからです。あなたはそれを知りませんでした。
malloc()は通常、使用可能なヒープをさまざまなサイズのチャンクに分割することで実装されます。あなたの場合、malloc()は2つの連続した1024(または16)バイトのチャンクを返します。言及した8バイトのスペースは、簿記情報のためにmalloc()によって使用されます。
舞台裏で何が起こっているのかを理解するには、Doug Leaのmalloc()実装ノートを参照してください: http://g.oswego.edu/dl/html/malloc.html
malloc()
には独自のオーバーヘッドがあります。
言うまでもなく、2つの連続した割り当てが最初から隣り合っているという保証はありません。
malloc
がnull以外を返す場合、プログラムに割り当てられているメモリ は、<=>に渡したサイズを持ちます。 <=>の2つの差分呼び出しの戻り値間のポインターの差分を取ると、任意の値を持つことができ、最初に割り当てられたブロックのブロックサイズとは何の関係もありません(ほとんどありません)。
これを見つけました。詳細については、以下のリンクを確認してください。
割り当て
ブロックは、次の式を使用して、要求されたバイトをバケット配列内のインデックスに最初に変換することにより、空きプールから割り当てられます。
必要=リクエスト+ 8
必要に応じて<!> lt; = 16 それから バケット= 0
必要に応じて<!> gt; 16、 それから バケット=(log(needed)/ log(2)は最も近い整数に切り捨てられます)-3
バケットに固定されたリスト内の各ブロックのサイズは、ブロックサイズ= 2バケット+ 4です。バケット内のリストがnullの場合、sbrkサブルーチンを使用してメモリが割り当てられ、リストにブロックが追加されます。ブロックサイズがページより小さい場合、sbrkサブルーチンを使用してページが割り当てられ、ブロックサイズをページサイズに分割することで到達したブロック数がリストに追加されます。ブロックサイズがページ以上の場合、必要なメモリはsbrkサブルーチンを使用して割り当てられ、単一のブロックがバケットの空きリストに追加されます。空きリストが空でない場合、リストの先頭のブロックが呼び出し元に返されます。リストの次のブロックが新しいヘッドになります。
ポインターが次の配列のサイズになる前、32/64ビット整数です(符号付きか符号なしかわからない)
割り当てられたメモリの量は8バイト余分になっているようですか? malloc()
システム上の実装は、ヒープセクションの大きさなどのメタデータ情報を維持するために余分なバイトを割り当てているようです開始アドレスなどの情報。
プラットフォームによって異なりますが。
X86システムでは、17
を要求している場合でも、malloc(0)
は<=>バイトの最小値を割り当てます。
int main(void) {
int *p = malloc(0);
if(p == NULL) {
/* error handling */
}
printf("%d\n",p[-1]);/ *it prints 17 bytes */
/* some code */
return 0;
}
malloc()は連続したメモリを割り当てることができますが、malloc()を2回呼び出すと、2つの変数を減算して割り当てられたメモリが連続することを期待できません...
ただし、割り当てられたメモリは、カーネル実装の一部である仮想メモリであり、メモリ管理(VFS)は特定のものです。アプリケーションの機能には影響しません。