可変長配列を使用するための任意のオーバーヘッドはありますか?
-
19-09-2019 - |
質問
可変長配列を使用していくつかのオーバーヘッドがありますか?配列のサイズは、実行時にコマンドライン引数で渡されていませんか?なぜそれが自動的かつ動的アレイを割り当てると比較して、導入された
解決
VLAが(コンパイル時のサイズのアレイ名前「通常」と比較して)いくつかのオーバーヘッドを持っています。
まず、それは実行時の長さを有し、しかも言語ランタイム(sizeof
を使用して)で、アレイの実際のサイズを取得するための手段を提供します。これはすぐに、配列の実際の大きさはどこかに保存しなければならないことを意味します。これは、いくつかの軽微ごとの配列のメモリのオーバーヘッドになります。 VLAが唯一の自動オブジェクトとして宣言することができますので、このメモリのオーバーヘッドは、誰もが今までに気付くだろうものではありません。それはちょうど、整数型の余分なローカル変数を宣言するようなものです。
次に、VLAは、通常、スタック上に割り当てられている、しかし、その可変サイズの、一般的な場合には、メモリ内のその正確な位置はコンパイル時に知られていません。このため実装が通常のメモリブロックへのポインタとしてそれを実装する必要があります。これは、再度、上述の理由のために完全に無意味であり、(ポインタのための)いくつかの追加のメモリオーバーヘッドを導入します。私たちは実際の配列を見つけるためにポインタ値を読み出すために持っているので、これはまた、わずかなパフォーマンス・オーバーヘッドを紹介します。これは、あなたがmalloc
-EDアレイにアクセスする際に取得する(と名付けコンパイル時のサイズの配列を得ることはありません)同じオーバーヘッドである。
VLAのサイズは、実行時の整数値であるので、それは、もちろん、コマンドライン引数として渡すことができます。その大きさはどこから来るVLAは気にしません。
VLAが低い割り当て/割り当て解除コストでランタイムサイズ配列として導入しました。彼らは(実質的にゼロ割り当て、割り当て解除のコストを持っていますが、固定サイズ)、「普通」という名前のコンパイル時のサイズの配列とmalloc
-EDアレイ(きた実行時の大きさが、比較的高い割り当て、割り当て解除のコスト)の間に収まります。
VLAが[ほぼ]従う一般的な場合に、それらがmalloc
-EDアレイを置き換えることができないことを意味自動(すなわちローカル)オブジェクト、同じスコープ依存寿命ルール。あなたは典型的な自動寿命の迅速な実行時のサイズの配列を必要とするとき、これらの適用は、状況に限定されます。
他のヒント
があり、可変長配列を持ついくつかの実行時のオーバーヘッドですが、あなたはそれを測定するためにかなり努力しなければならないであろう。 sizeof(vla)
が可変長配列である場合にvla
はコンパイル時定数ではないことに注意してください。
配列のサイズは、実行時に関数に渡すことができます。あなたはコマンドライン引数からサイズを取り、整数にそれを変換し、実行時に関数にそれを渡すことを選択した場合、それは可能 - それは動作します。
。 変数は自動的に正しいサイズに割り当てられ、自動的に関数からの出口に解放されるので、可変長アレイが使用されます。これは、(あなたが主に最小限のサイズで動作可能な最大サイズのための十分なスペースを割り当てる)過剰割り当てスペースを回避し、メモリに問題がクリーンアップ回避ます。
あなたは動的ではなく、全てが、配列のリーディング次元の固定サイズで立ち往生しているよりも、すべての寸法を設定することができます -また、多次元配列で、の私の知る限り、のそれはより多くのFortranのように振る舞います。
<時間> VLAのためのいくつかの実行時のオーバーヘッドの具体的な証拠 - 少なくともSPARC上のGCC 4.4.2(Solarisの10)と
。の下に2つのファイルを考えてみます:
vla.c - 使用して可変長配列
#include <assert.h>
#include <stddef.h>
extern size_t identity_matrix(int n, int m);
size_t identity_matrix(int n, int m)
{
int vla[n][m];
int i, j;
assert(n > 0 && n <= 32);
assert(m > 0 && m <= 32);
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
vla[i][j] = 0;
}
vla[i][i] = 1;
}
return(sizeof(vla));
}
fla.c - 使用して固定長配列
#include <assert.h>
#include <stddef.h>
extern size_t identity_matrix(int n, int m);
size_t identity_matrix(int n, int m)
{
int fla[32][32];
int i, j;
assert(n > 0 && n <= 32);
assert(m > 0 && m <= 32);
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
fla[i][j] = 0;
}
fla[i][i] = 1;
}
return(sizeof(fla));
}
コンパイルし、オブジェクトファイルサイズ
比較のために、ローカル配列の名前は(vla
対fla
)異なっており、それが宣言されたときに、アレイ上の寸法が異なっている - そうでない場合、ファイルは同じである
I使用してコンパイルされます:
$ gcc -O2 -c -std=c99 fla.c vla.c
オブジェクトファイルサイズが多少異なる - 「のLS」によって、および「サイズ」の両方によって測定される:
$ ls -l fla.o vla.o
-rw-r--r-- 1 jleffler rd 1036 Jan 9 12:13 fla.o
-rw-r--r-- 1 jleffler rd 1176 Jan 9 12:13 vla.o
$ size fla.o vla.o
fla.o: 530 + 0 + 0 = 530
vla.o: 670 + 0 + 0 = 670
私はどのくらいのオーバーヘッドが固定されており、どのくらいの変数ですが、オーバーヘッドはVLAを使用してあります見に広範なテストを行っていませんでした。
可変長配列を使用していくつかのオーバーヘッドがある場合は、私だけだろうか?
いいえ
配列のサイズは、実行時にコマンドライン引数を経由して渡すことができますすることができますか?
はいます。
なぜ自動かつ動的アレイを割り当てると比較して、導入された
自動コンパイル時にのみ知られている固定サイズができ、割り当てられます。
の動的割り当て(malloc
)大きなメモリ空間を有しているが、アクセスに遅い。ヒープの、上のアレイを記憶する
VLAは、のスタックの中に配列を配置することによって動作します。これは、を、配分とアクセスが非常に高速になりますが、のスタックは(数KBの)通常小さく、VLAがスタックをオーバーフローしたときに、それは無限再帰と区別がつかないのです。
(せいぜい、それはスタックポインタのほかになるはずである)のVLAのために非常にわずかなオーバーヘッドがあるはずです。動的割り当ては、手動メモリ管理を必要とし、VLAのスタックベースの割り当てよりも遅くなり、アレイの「自動」宣言は、配列サイズのコンパイル時の発現を必要とします。しかし、スタックオーバーフローが発生した場合、それは未定義の動作の原因となりますことを心に留めておくので、比較的小さいのVLAを維持します。
あなたは、コマンドライン引数を経由して、配列のサイズを渡すことができますが、あなたが自分で処理するコードを記述する必要があります。