ファイル内のさまざまなサイズのレコードをゼロにする必要があります。これを行うために、私は現在、ダミーレコードを割り当て、memset
それらをゼロに割り当て、これらを書き込み関数に渡します。
常にゼロになることが保証されている(そして十分に大きいサイズの)領域がありますか?代わりにポイントして、メモリの割り当てとゼロ化を繰り返す必要がなくなりますか?
ファイル内のさまざまなサイズのレコードをゼロにする必要があります。これを行うために、私は現在、ダミーレコードを割り当て、memset
それらをゼロに割り当て、これらを書き込み関数に渡します。
常にゼロになることが保証されている(そして十分に大きいサイズの)領域がありますか?代わりにポイントして、メモリの割り当てとゼロ化を繰り返す必要がなくなりますか?
レコードサイズに妥当な上限がある場合は、ゼロを含むグローバル読み取り専用変数を割り当てます。(これは静的期間オブジェクトであるため、自動的にゼロに初期化されます。)
const unsigned char zero_filled_buffer[MAX_RECORD_SIZE]; /*at file scope*/
書き込み関数がC fwrite
、POSIX write
、またはその他の関数である場合はwrite
、ループで呼び出すことができるため、バッファーは最大のレコードと同じ大きさである必要はなく、最大のチャンクと同じ大きさである必要はありません。一度に書いてください。
このような変数は、一般的なホストされた実装では、実行可能ファイルのスペースをゼロにします。追加:C標準に関する限り、上記の宣言はまったく同じですがconst unsigned char zero_filled_buffer[MAX_RECORD_SIZE] = {0};
、一部のコンパイラ(gccを含む)は、明示的に追加した場合は実行可能ファイルにゼロを含めます= {0}
が、初期化子を省略した場合は含めません。
仮想メモリを備えたシステム上のスマートプログラムローダーは、仮想メモリシステムを利用して、そのようなすべてのオブジェクトに物理RAMの単一の共有読み取り専用ゼロフィルページを使用できます。実際にそうするかどうかはわかりません。追加:たとえば、Linux(Debian lenny amd64)はそうではありません。
別のPOSIXアプローチはmmap
、ファイルとmemset
ゼロフィルバッファーの呼び出しです。
callocを参照してください。
この関数は、それぞれのサイズがバイト単位
calloc()
の要素の配列に未使用のスペースを割り当てます。スペースはすべてのビットに初期化されます。nelem
elsize
0
または(私はこれを試しませんでした)、割り当てがまったく必要ない場合は、ブロックopen
をmmap
/dev/zero
読み取りrecord_size
、レコードを上書きしているファイルに書き込むことができます。
少なくともLinuxでメモリを割り当てるmmap()
と、バッファがゼロになります。欠点は、必要なメモリを割り当てるだけでなく、ページサイズの倍数だけを割り当てることができることです。
#include <unistd.h>
long sz = sysconf(_SC_PAGESIZE);
前述のように、必要な最大のリージョンを1回だけ割り当てる必要があります。そのサイズ以下の領域が必要なときはいつでもそれを渡すことができます。
ほとんどの実装では、RAMにマップされていないアドレス空間の部分はありませんが、読み取られると無害にゼロが読み取られます。そんなものがあればいいのかもしれませんが、私は気づいていません。
一部の組み込みシステムでは、フラッシュメモリ書き込みルーチンを記述しているため、nullポインターが与えられた場合、ソースデータは(アプリケーションに応じて)すべてFFであると見なされます。これは、次のチャンクをクリアする必要がある場合があるためです。ファイルであり、最後の書き込みコードでnullポインターの場合を処理するということは、フラッシュブロックを見つけて割り当てるコードをwrite-meaningful-dataの場合とwrite-blank-dataの場合で共有できることを意味します。注意点の1つは、書き込みを複数の部分に分割する場合、I/O書き込みに渡す前にnullポインタにオフセットを追加してはならないということです。
はい、これらのレコードのいずれかに十分な大きさのブロックを割り当て、一度ゼロにします。そのブロックのアドレスを、実際にゼロにしたいレコードのサイズとともに、毎回書き込み関数に渡します。書き込み用のバッファーを渡しても、期限切れになることはありません。念のために言っておきますが、書き込みは渡したバッファを解放しません。それはあなた次第です。
常にゼロになる大きなメモリ領域が必要な場合は、自分で割り当てて、ゼロに設定する必要があります。それを回避する必要はありませんが、一度だけ実行する必要があります。少なくとも、一度に必要になるゼロ化されたメモリの最大量と同じ大きさであることを確認してください。
次に、ゼロ化されたメモリにポインタを渡す必要があるときはいつでも、割り当てたこのブロック内にポインタを渡すことができます。
これが動作することが保証されている、実行時の可能性(でコンパイルgcc zeroed_mem_region.c -Wall -std=gnu99
):
#include <sys/mman.h>
#include <assert.h>
#include <stdio.h>
size_t const zeroed_size = 512;
char const *zeroed;
int main()
{
zeroed = mmap(
NULL,
zeroed_size,
PROT_READ,
MAP_PRIVATE|MAP_ANONYMOUS,
-1,
0);
printf("zeroed region at %p\n", zeroed);
for (size_t i = 0; i < zeroed_size; ++i) {
assert(zeroed[i] == 0);
}
printf("testing for writability\n");
((char *)zeroed)[0] = 1;
return 0;
}
ゼロ化はchar const *
テスト用であることに注意してください。実際には、これはになりますvoid const *
。
SIGSEGV
)mmap(2)
)システム情報APIを使用してシステムページサイズを取得し(正確な名前を思い出せません)、1ページのメモリを割り当て、ゼロに設定し、連続して繰り返し書き込みます。
書き込み関数の速度は、memsetよりも桁違いに遅くなります*。
プロファイルしてください!
*フラッシュドライブでも