6

このコードをテストして、c++ が実際に new 演算子用に予約したメモリ量を調べました。

#include<iostream>
using namespace std;
int main() {

  cout << "alignment of " << alignof(int) << endl;
  int *intP1 = new int;
  *intP1 = 100;
  cout << "address of intP1 " << intP1 << endl;
  int *intP2 = new int;
  *intP2 = 999;
  cout << "address of intP2 " << intP2 << endl;
  int *intP3 = new int;
  cout << "address of intP3 " << intP3 << endl;
  *intP3 = 333;

  cout << endl;
  cout << (reinterpret_cast<char *>(intP3)-reinterpret_cast<char *>(intP2)) << endl;
  cout << intP3-intP2 << endl;
  cout << endl;

  cout << *(intP1) << endl;
  cout << *(intP1+4) << endl;
  cout << *(intP1+8) << endl;
  cout << *(intP1+16) << endl;
  delete intP1;
  delete intP2;
  delete intP3;
  return 0;
}

-std=c++11 フラグを付けてコードをコンパイルして実行した後、x86_64 マシンから取得したものを次に示します。

    alignment of int4
    address of intP1 = 0xa59010
    address of intP2 = 0xa59030
    address of intP3 = 0xa59050

    the distance of intP3 and intP2 = 32

    intP1 value = 100
    is this a padding value = 0
    intP2 value = 999
    intP3 value = 333

new を使用して整数に 4 バイトのメモリを割り当てると、実際には 8 つの整数の合計スペースである 32 バイトのブロックが予約されたようです。c++ アライメントの説明によると、64 ビット マシンの場合、メモリは 16 バイトでアライメントされますが、ここでの距離が 32 バイトなのはなぜですか?

誰かがこれを整理するのを手伝ってくれますか? 前もって感謝します。

4

7 に答える 7

5

アラインメントとは関係ありません。内部メモリ アロケータの動作による追加のオーバーヘッドです。通常、各メモリ ブロックには、ヒープの構造を維持するために使用される前部および/または後部に追加の隠し情報があります。オーバーヘッドの正確な量は、プラットフォームごと、および実装ごとに異なります。

たとえば、Doug Lea のmalloc場合、割り当てごとに 4 ~ 8 バイト (32 ビット ポインター) または 8 ~ 16 バイト (64 ビット ポインター) の余分なオーバーヘッドがあり、最小割り当てサイズは 16 バイト (32 ビット) または 32 バイト ( 64ビット)。つまり、1 バイトの割り当てでも、メモリ アロケータは合計 16 バイトのトラッキング オーバーヘッドを必要とします。

于 2012-11-13T23:40:51.827 に答える
2

32 バイトの違いは、アライメントのためだけではありません。実際、アドレス0xa59010が 32 で整列されているのではなく、16 で整列されているだけであることに注意してください。したがって、アドレスが 32 バイトではなく 16 バイトしか離れていなくても、アドレスのアラインメントは悪化しません。

むしろ、32 バイトの違いは、メモリ アロケータのオーバーヘッド/非効率性です。アロケータが次のことを疑っています。

  • 16 アラインされたアドレスを提供するのに役立ちます。これは 128 ビットの SSE 型に必要なものなので便利ですが、それがアロケーターが 16 アライメントである主な理由なのか、アロケーターにとって便利なだけなのかはわかりません。
  • 簿記情報の割り当ての「前」にいくらかのスペースが必要です。これは16バイト(2つのポインターまたはポインターとサイズ)になる場合がありますが、そうでない場合でも16バイトに切り上げられます。
  • 実際のデータには 4 バイトしか必要ありませんが、16 バイトのブックキーピングと 16 バイトのアラインメントのため、割り当て間の最小距離は 32 バイトです。したがって、4バイトの割り当てを行うと、12バイトの「スラックスペース」/「内部フラグメンテーション」/「無駄」があります。

しかし、それは単なる推測であり、使用しているアロケーターについては調べていません。

于 2012-11-13T23:42:43.023 に答える
1

のデバッグ バージョンでnewは、かなりの量のパディングを追加してガード スペースを確保できるため、一部のヒープの破損を検出できます。違いがあるかどうかを確認するには、デバッグ ビルドとリリース ビルドの両方で実行する必要があります。

于 2012-11-13T23:48:47.240 に答える
0

C ++標準では、各ヒープ割り当てのオーバーヘッドの量は保証されません。配置に関係なく、アロケータは通常、余分なオーバーヘッドを追加します。アロケータが事前にサイズ設定されたバケットから小さな割り当てを実行することは非常に一般的です。ここでは、最小のバケットは割り当てごとに32バイトであるように見えますが、これは珍しいことではありません。バケットが16バイト未満のアロケータが実際に見つかることはめったにありません。

複数のint、たとえばint [2]を割り当てる場合、使用されるメモリサイズが同じであることに気付くでしょう:32バイト。

また、同じサイズの2つの割り当てが連続しているというC++標準またはアロケータからの保証がないことにも注意してください。これはほとんどの場合尊重される可能性がありますが、信頼すべきではありません。

于 2012-11-13T23:52:33.480 に答える
0

オペレーティング システムが 3 つのポインタ と を互いに隣接して割り当てる必要はまったくありintP1ませintP2intP3。コードは割り当てでオーバーヘッドを検出している可能性があります (もちろん、ある程度のオーバーヘッドがあることは合理的な仮定です) が、スペーシングが必ずしもすべてのアロケーターのオーバーヘッドであることを証明するには不十分です。

于 2012-11-13T23:48:56.037 に答える
0

ポインタとメモリ値の両方があります。これにより、すでに述べた2つのメモリブロックが割り当てられますが、これは16バイトです。2x16=32。

これにより、あなたが探していた結果が得られると思います。

  cout << "alignment of " << alignof(int) << endl;
  int intP1 = 100;
  cout << "address of intP1 " << &intP1 << endl;
  int intP2 = 999;
  cout << "address of intP2 " << &intP2 << endl;
  int intP3 = 333;
  cout << "address of intP3 " << &intP3 << endl;
于 2012-11-13T23:37:37.123 に答える
0

int4これは、4 ビットではなく 4 バイトを占めることを意味します。コンパイラが表示するものはすべて、実際には正確です! プリミティブとプリミティブの意味に関するドキュメントを次に示します。int

これは、4 ビット整数を定義する方法に関するチュートリアルです

alignofそれはアーキテクチャに依存していることに言及させてください。一部のアーキテクチャintでは、4 ではなく 16 ビット int または 2 バイトを意味します。

于 2012-11-13T23:38:52.690 に答える