111

ハイパフォーマンスコンピューティング(10 ^ 5〜10 ^ 6コア)にMPIを使用するプロジェクトの誰かのC++コードを確認しています。このコードは、異なるアーキテクチャ上の(潜在的に)異なるマシン間の通信を可能にすることを目的としています。彼は次のようなコメントを書いています。

通常はnewanddeleteを使用しますが、ここではandを使用mallocしていfreeます。new一部のコンパイラは、使用時にデータのパディングが異なり、異なるプラットフォーム間でのデータ転送でエラーが発生するため、これが必要です。これはでは起こりませんmalloc

newこれは、私が標準対malloc質問から知っていることには適合しません。

new/deleteとmalloc/freeの違いは何ですか?コンパイラがオブジェクトのサイズを異なる方法で計算できるという考えを示唆しています(しかし、なぜそれが使用と異なるのsizeofですか?)。

mallocと配置の新規と新規newの比較はかなり人気のある質問ですが、そうでない場合にコンストラクターを使用することについてのみ説明mallocします。これはこれには関係ありません。

mallocはアライメントをどのように理解しますか?記憶はどちらかと適切に整列することが保証されている、newまたはmalloc私が以前考えていたものであると言います。

私の推測では、彼は過去に自分のバグを誤診し、それを推測してnewmallocさまざまな量のパディングを行っていたと思いますが、これはおそらく真実ではないと思います。しかし、私はグーグルや以前の質問で答えを見つけることができません。

私を助けてください、StackOverflow、あなたは私の唯一の希望です!

4

8 に答える 8

26

IIRCには1つの厄介な点があります。malloc標準タイプに合わせて調整されたアドレスを返すことが保証されています。n以下の::operator new(n)標準タイプにアラインされたアドレスを返すことが保証されているだけであり、が文字タイプでない場合は、にアラインされたアドレスを返すだけで済みます。Tnew T[n]T

ただし、これは、ポインタの下部の数ビットを使用してフラグを格納するなど、実装固有のトリックを実行している場合や、アドレスに依存して厳密に必要以上の配置を行う場合にのみ関係します。

オブジェクト内のパディングには影響しません。オブジェクトが占有するメモリをどのように割り当てたかに関係なく、必然的にまったく同じレイアウトになります。そのため、この違いによってデータの転送中にエラーが発生する可能性があることを理解するのは困難です。

そのコメントの作者が、スタック上のオブジェクトまたはグローバルのオブジェクトについて、「mallocのようにパディングされている」か「新しいのようにパディングされている」かどうかにかかわらず、何か兆候はありますか?それはアイデアがどこから来たのかについての手がかりを与えるかもしれません。

malloc(sizeof(Foo) * n)彼は混乱しているかもしれませんが、彼が話しているコードは、 vsとの単純な違い以上のものである可能性がありnew Foo[n]ます。多分それはもっと似ています:

malloc((sizeof(int) + sizeof(char)) * n);

対。

struct Foo { int a; char b; }
new Foo[n];

つまり、彼は「mallocを使用している」と言っているかもしれませんが、 「構造体を使用する代わりに、データを位置合わせされていない場所に手動でパックしている」という意味です。構造体を手動でパックするために実際mallocには必要ありませんが、それを認識できないと、混乱は少なくなります。有線で送信されるデータレイアウトを定義する必要があります。構造体が使用される場合、実装が異なればデータのパディングも異なります。

于 2012-11-08T11:39:24.560 に答える
5

同僚がnew[]/delete[]マジッククッキーを念頭に置いていた可能性があります(これは、実装がアレイを削除するときに使用する情報です)。new[]ただし、 (アロケータではなく)によって返されたアドレスで始まる割り当てが使用された場合、これは問題にはなりませんでした。

パッキングの可能性が高いようです。ABIのバリエーションにより、(たとえば)構造の最後に異なる数の末尾バイトが追加される可能性があります(これはアライメントの影響を受けます。配列も考慮してください)。mallocを使用すると、構造の位置を指定できるため、外国のABIに簡単に移植できます。これらの変動は通常、トランスファー構造の位置合わせとパッキングを指定することで防止されます。

于 2012-11-08T10:36:33.720 に答える
3

私はあなたが正しいと思います。newパディングは、またはではなくコンパイラによって行われmallocます。new配列または構造体を使用せずに、またはmallocまったく使用せずに宣言した場合でも、パディングに関する考慮事項が適用されます。いずれにせよ、プラットフォーム間でコードを移植するときに、さまざまな実装がどのようnewmalloc問題を引き起こす可能性があるかはわかりますが、プラットフォーム間でデータを転送する際にどのように問題が発生する可能性があるかは完全にわかりません。

于 2012-11-08T10:06:53.827 に答える
3

mallocオブジェクトのレイアウトは、またはを使用して割り当てられたかどうかに依存することはできませんnew。どちらも同じ種類のポインタを返します。このポインタを他の関数に渡すと、オブジェクトがどのように割り当てられたかがわかりません。がどのように割り当てられたかではなくsizeof *ptr、の宣言に依存しているだけです。ptr

于 2012-11-08T10:44:08.733 に答える
0

これは、このことがどこから来ているのかについての私の大げさな推測です。あなたが言ったように、問題はMPIを介したデータ送信にあります。

個人的には、MPIを介して送受信したい複雑なデータ構造に対して、charの配列にすべてをパック/アンパックするシリアル化/逆シリアル化メソッドを常に実装しています。ここで、パディングにより、構造のサイズがそのメンバーのサイズよりも大きくなる可能性があることがわかっているため、データ構造のパディングされていないサイズを計算して、送受信されているバイト数を知る必要があります。

たとえば、前述の手法を使用してMPIを介して送受信する場合std::vector<Foo> A、結果として得られる文字の配列のサイズがA.size()*sizeof(Foo)一般的であると想定するのは誤りです。つまり、シリアル化/逆シリアル化メソッドを実装する各クラスは、配列のサイズを報告するメソッドも実装する必要があります(または、配列をコンテナーに格納することをお勧めします)。これバグの背後にある理由になる可能性があります。ただし、このスレッドで指摘されているように、それはnewvsとは何の関係もありません。malloc

于 2012-11-12T18:37:09.137 に答える
0

プレーンな古いデータ構造のレイアウトを制御したい場合は、MSVisualコンパイラを使用します#pragma pack(1)。このようなプリコンパイラディレクティブは、gccなどのほとんどのコンパイラでサポートされていると思います。

これにより、構造のすべてのフィールドが空のスペースなしで前後に整列されます。

もう一方のプラットフォームが同じことを行う場合(つまり、1のパディングでデータ交換構造をコンパイルした場合)、両側で取得されたデータは適切に適合します。したがって、C++でmallocを使用する必要はありませんでした。

最悪の場合、C ++でmallocを直接使用するのではなく、いくつかのトリッキーなことを実行するために、新しい演算子をオーバーロードすることを検討しました。

于 2012-11-14T00:05:18.190 に答える
0

c ++では、 newキーワードは、データ構造に関して特定のバイトのメモリを割り当てるために使用されます。たとえば、クラスまたは構造を定義し、そのオブジェクトにメモリを割り当てたいとします。

myclass *my = new myclass();

また

int *i = new int(2);

ただし、すべての場合で、定義されたデータ型(class、struct、union、int、charなど)が必要であり、そのオブジェクト/変数に必要なメモリのバイトのみが割り当てられます。(つまり、そのデータ型の倍数)。

ただし、malloc()メソッドの場合は、任意のバイトのメモリを割り当てることができ、常にデータ型を指定する必要はありません。ここでは、malloc()のいくつかの可能性でそれを観察できます。

void *v = malloc(23);

また

void *x = malloc(sizeof(int) * 23);

また

char *c = (char*)malloc(sizeof(char)*35);
于 2015-05-14T08:11:08.797 に答える
-1

mallocは関数の一種であり、newはc++のc++のデータ型の一種です。mallocを必要以上に使用する場合は型キャストを使用する必要があります。そうでない場合はコンパイラでエラーが発生し、メモリの割り当てに新しいデータ型を使用する場合は不要です。タイプキャストする

于 2015-12-23T12:28:20.430 に答える