創建一個 32MB (65536 塊 × 512 字節/塊) 的二進制文件 cq.dat,全部填充 0x00,模擬磁盤鏡像初始化。對比逐字節寫入與內存塊寫入兩種方案的實現差異與性能。
// 註釋掉的代碼
for (i = 0; i < BLOCK_NUM; i++) {
for (j = 0; j < BLOCK_SIZE; j++) {
fprintf(fp, "%c", '\0'); // 每字節一個系統調用 + 格式化解析開銷
}
}
缺點:fprintf 解析格式字符串、調用 write 系統調用,每字節一次,32MB 需 3355 萬次調用,極其低效,僅供邏輯驗證。
#include
#include // Windows 內存泄漏檢測
#include
#include
using namespace std;
FILE *fp;
const char SP_NAME[] = "cq.dat";
const int BLOCK_NUM = 65536; // 64K 塊
const int BLOCK_SIZE = 512; // 512 字節/塊
const int BITE_NUM = 33554432; // 總字節 = 64K * 512 = 32MB
void init() {
fp = fopen(SP_NAME, "wb"); // 二進制寫入模式
if (!fp) return;
// 1. 一次性分配 32MB 內存
char *memory = (char *)malloc(BITE_NUM);
if (!memory) { fclose(fp); return; }
// 2. 內存中高效置零 (memset 優化為向量化指令)
memset(memory, 0, BITE_NUM);
// 3. 一次性寫入文件 (單次 fwrite 系統調用)
fwrite(memory, 1, BITE_NUM, fp);
fclose(fp);
free(memory); // 釋放內存
}
int main() {
init();
return 0;
}
| 技術點 | 說明 |
|---|---|
fopen(..., "wb") |
二進制寫入模式,Windows 下關鍵:禁用 \n→\r\n 轉換,確保字節流純粹。 |
malloc(BITE_NUM) |
堆上分配 32MB 連續內存。32 位程序需注意地址空間;64 位無壓力。 |
memset(memory, 0, size) |
編譯器內建函數,通常優化為 rep stosb 或 AVX/SSE 向量化存儲,GB/s 級速度。 |
fwrite(ptr, 1, size, fp) |
以字節為單位寫入,實際調用 WriteFile (Win) / write (Linux) 一次性傳輸 32MB,極少上下文切換。 |
free(memory) |
及時釋放,防內存洩漏。配合 crtdbg.h 可在調試時自動檢測泄漏。 |
| 方案 | 系統調用次數 | 用戶態 CPU | 預估耗時 |
|---|---|---|---|
| 逐字節 fprintf | 33,554,432 | 極高 (格式化解析) | 數秒 ~ 數十秒 |
| 塊內存 fwrite | 1 (fwrite) + 少量 malloc/free | 極低 (memset 向量化) | < 10 ms |
fprintf/fscanf)。posix_memalign 或 _aligned_malloc,可啟用 DMA/直接 I/O 進一步提速。fopen/malloc/fwrite 返回值,記錄 errno/GetLastError。_O_BINARY 確保二進制模式;Linux 默認即二進制,無差異。本實驗以 32MB 零填充文件為例,直觀對比了「逐字節高級 I/O」與「塊內存低級 I/O」的天壤之別。操作系統實驗乃至所有系統級編程的核心原則:**減少用戶態/內核態切換、利用硬件向量化指令、以空間換時間 (大緩衝區)**。掌握 malloc + memset + fwrite 這一「鐵三角」模式,是高性能文件/網絡/設備 I/O 開發的入門必修課。