4

新しいアロケータの動作と、データが連続して配置されない理由を調べようとしていました。

私のコード:

struct ci {
    char c;
    int i;
}

template <typename T>
void memTest()
{
    T * pLast = new T();
    for(int i = 0; i < 20; ++i) {
         T * pNew = new T();
         cout << (pNew - pLast) << " ";
         pLast = pNew;
    }
}

だから私はこれをchar、int、ciで実行しました。ほとんどの割り当ては最後から固定長であり、使用可能なブロックから別のブロックへのジャンプが奇妙な場合がありました。

sizeof(char):1
平均ジャンプ:64バイト

sizeof(int):4
平均ジャンプ:16

sizeof(ci):8(intは4バイトの整列に配置する必要があります)
平均ジャンプ:9

アロケータがこのようにメモリを断片化している理由を誰かが説明できますか?また、charのジャンプがintよりもはるかに大きく、intとcharの両方を含む構造であるのはなぜですか。

4

5 に答える 5

10

2つの問題があります:

  • ほとんどのアロケータは、ブロックの開始前にいくつかの追加データを格納します(通常はブロックサイズといくつかのポインタ)

  • 通常、アライメント要件があります。最近のオペレーティングシステムは、通常、少なくとも8バイトの境界に割り当てます。

したがって、ほとんどの場合、連続する割り当ての間に何らかのギャップが生じます。

もちろん、このような特定の動作に依存することは絶対にしないでください。実装は自由に実行できます。

于 2010-04-27T20:22:27.080 に答える
6

コードにバグが含まれており、ポインターが(char *)にキャストされる距離を知ることができます。そうでない場合、デルタはsizeof(T)になります。

于 2010-04-27T20:23:24.103 に答える
3

これは断片化ではなく、割り当てのサイズを丸められたブロックサイズに切り上げるだけです。

一般的なプログラミングでは、のような汎用アロケータによって返されるメモリアドレスのパターンに注意を払うべきではありませんnew。割り当て動作を気にするときは、常に特別な目的のアロケータ(boost :: pool、自分で作成したものなど)を使用する必要があります。

例外は、アロケータを研究している場合です。この場合、K&Rnewのコピーを取得して単純なアロケータを取得するよりも悪い結果になる可能性があります。これは、どのようにメモリを取得するかを理解するのに役立ちます。

于 2010-04-27T20:47:34.920 に答える
2

一般に、特定のメモリ配置に依存することはできません。メモリアロケータの内部簿記データと配置要件の両方が、ブロックの配置に影響を与える可能性があります。ブロックを連続して割り当てる必要はありません。

さらに、一部のシステムでは「見知らぬ人」の行動さえも得られます。最近の多くのLinuxシステムでは、ヒープのランダム化が有効になっています。この場合、新しく割り当てられた仮想メモリページがランダムなアドレスに配置され、特定の種類のセキュリティの脆弱性の悪用がより困難になります。仮想メモリでは、仮想アドレス空間が密集している必要がないため、割り当てられたブロックアドレスが異なるからといって、必ずしも物理メモリが断片化されているとは限りません。

于 2010-04-27T20:28:06.250 に答える
0

小さな割り当ての場合、boostには私が使用したboost::simple_segregated_storageと呼ばれる非常に単純なアロケータがあります

これは、すべて同じサイズの空きブロックと使用済みブロックのスリストのコピーを作成します。設定されたブロックサイズにのみ割り当てる限り、外部の断片化は発生しません(ただし、ブロックサイズが要求されたサイズよりも大きい場合は、内部の断片化が発生する可能性があります)。これで使用すると、O(1)も実行されます。マナー。テンプレートプログラミングで一般的なような小さな割り当てに最適です。

于 2010-04-27T21:11:38.783 に答える