C++ で線形代数プログラムを作成するときは、Armadillo ライブラリを使用します。これはテンプレートに基づいており、コンパイル時に適切なメモリ バッファが静的に割り当てられるため、必ずしも追加のメモリ割り当てを必要としない任意の長さのベクトルを定義する方法を提供します。コンパイラを使用するとarma::Col<double>::fixed<3>
、その場で「新しい型」が作成されるため、ベクターには正確に 3 つの double のバッファーが含まれます。
現在、C で線形代数プログラムに取り組んでおり、GNU Scientific Library (GSL) を使用しています。3D ベクトルをインスタンス化するために、次のようにしgsl_vector_alloc(3)
ますgsl_vector*
。問題は、この操作によってメモリのごく一部が動的に割り当てられ、プログラムの実行中に何百万回も発生することです。malloc
私のプログラムは、数千万回の操作を実行するために多くのリソースを浪費していfree
ます。
の内部構造を調べましたgsl_vector
:
typedef struct
{
size_t size;
size_t stride;
double * data;
gsl_block * block;
int owner;
} gsl_vector;
ライブラリが正しく機能data
するには、ベクトルの最初の要素を指す必要があります。通常は、次のgsl_block
ような構造内にあります。
typedef struct
{
size_t size;
double * data;
} gsl_block;
data
別のポインターが含まれています。したがって、単純な 3D ベクトルをインスタンス化する場合、次の一連のmalloc
s が発生します。
gsl_vector
構造体は'd (malloc
x86_64 では約 40 バイト) です。gsl_block
構造体はmalloc
'd (16 バイト) であり、gsl_vector のポインターblock
は、割り当てられたばかりの gsl_block のメモリ アドレスに設定されます。- 3 つの倍精度浮動小数点数の配列が'd になり、そのメモリ アドレスが両方のポインター (の 1 つと の 1 つ)に
malloc
割り当てられます。data
gsl_block
gsl_vector
2 つの を削除することで、パフォーマンスが 40% 向上しましたmalloc
。gsl_vector
3 つの double の配列を割り当て、のdata
ポインターgsl_vector
をこの配列のアドレスに設定するカスタム作成ルーチンを作成しました。gsl_vector
次に、 (ポインターではなく)を返します。
しかし、そうしても、何百万ものmalloc(3 * sizeof(double))
操作が行われます。
gsl_vector
構造体の内部に 3 つの double の配列を「埋め込む」ことができませんでした。ポインタが構造体自体の内部data
にあるものを指している場合(ハック!)、ベクトルが別の場所にコピーされるとポインタが無効になるためです!
何かアイデアはありますか (C++ に切り替えるか、独自の線形代数ライブラリを展開する以外に)? 私はどんな提案にもオープンです。