Memproses PDF standar (1MB hingga 10MB) di Delphi sangatlah mudah menggunakan kelas aliran standar seperti TFileStream atau TMemoryStream. Namun, saat Anda ditugaskan untuk memproses PDF berskala gigabyte, seperti skema CAD rekayasa yang besar, peta geospasial resolusi tinggi, atau arsip hukum yang terkumpul, teknik alokasi memori standar akan cepat rusak.
Jika Anda memuat PDF 2GB ke dalam TMemoryStream di aplikasi Delphi 32-bit, Anda akan langsung menemui pengecualian EOutOfMemory. Bahkan dalam aplikasi 64-bit, hal itu menyebabkan kesalahan halaman yang parah dan membuat server terhenti. Dalam artikel ini, kita akan menjelajahi cara mengoptimalkan kinerja I/O untuk file besar menggunakan File yang Dipetakan Memori (Memory-Mapped Files).
Masalah pada Aliran Standar
Saat Anda menggunakan TMemoryStream.LoadFromFile, OS membaca file dari disk, mengalokasikan RAM berurutan, dan menyalin data ke dalamnya. Untuk file 2GB, ini membuang RAM fisik sebesar 2GB dan membutuhkan waktu yang signifikan hanya untuk putaran baca disk.
Bahkan penggunaan TFileStream dapat bermasalah jika Anda sering melompat-lompat di dalam file (misalnya, mem-parsing tabel XRef PDF di akhir file, lalu melompat ke objek yang tersebar di seluruh file). Panggilan Seek dan Read yang terus-menerus menghasilkan overhead transisi kernel yang tinggi.
Solusinya: File yang Dipetakan Memori
Pemetaan memori (melalui fungsi API Windows CreateFileMapping dan MapViewOfFile) meminta OS untuk memetakan file secara langsung ke ruang alamat virtual aplikasi. Anda mendapatkan penunjuk ke data, dan Windows Virtual Memory Manager menangani paging data masuk dan keluar dari RAM fisik hanya saat Anda mengaksesnya.
Berikut adalah cara Anda dapat menerapkan pembaca file yang dipetakan memori berperforma tinggi di Delphi untuk pem-parsing-an PDF:
uses
Winapi.Windows, System.SysUtils, System.Classes;
type
TMemoryMappedFileReader = class
private
FFileHandle: THandle;
FMappingHandle: THandle;
FDataPtr: Pointer;
FFileSize: Int64;
public
constructor Create(const FileName: string);
destructor Destroy; override;
property Data: Pointer read FDataPtr;
property Size: Int64 read FFileSize;
end;
constructor TMemoryMappedFileReader.Create(const FileName: string);
var
HighSize, LowSize: DWORD;
begin
// Open the file with read permissions
FFileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if FFileHandle = INVALID_HANDLE_VALUE then
RaiseLastOSError;
// Get the 64-bit file size
LowSize := GetFileSize(FFileHandle, @HighSize);
FFileSize := (Int64(HighSize) shl 32) or LowSize;
// Create the mapping object
FMappingHandle := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, HighSize, LowSize, nil);
if FMappingHandle = 0 then
RaiseLastOSError;
// Map the file into the virtual address space
FDataPtr := MapViewOfFile(FMappingHandle, FILE_MAP_READ, 0, 0, 0);
if FDataPtr = nil then
RaiseLastOSError;
end;
destructor TMemoryMappedFileReader.Destroy;
begin
if FDataPtr <> nil then UnmapViewOfFile(FDataPtr);
if FMappingHandle <> 0 then CloseHandle(FMappingHandle);
if FFileHandle <> INVALID_HANDLE_VALUE then CloseHandle(FFileHandle);
inherited;
end;
Mengapa Pemetaan Memori Mendominasi Pem-parsing-an PDF
PDF adalah format akses acak. Parser mulai dengan membaca cuplikan di akhir file, menemukan tabel XRef, lalu melompat secara acak ke offset byte di seluruh file untuk memuat kamus dan aliran tertentu.
Dengan pemetaan memori:
- Salin-Nol (Zero-Copy): Data tidak disalin dari ruang kernel ke ruang pengguna; Anda membaca langsung dari cache file OS.
- Pemuatan Instan: Membuka PDF 2GB membutuhkan waktu beberapa milidetik, karena tidak ada data yang benar-benar dibaca dari disk hingga Anda melakukan dereferensi penunjuk.
- Paging yang Dikelola OS: Jika Anda hanya mem-parsing data 50MB dari file 2GB, OS hanya memuat 50MB tersebut ke dalam RAM fisik. Konsumsi memori tetap kecil.
Dengan menerapkan kelas aliran khusus yang didukung oleh file yang dipetakan memori, aplikasi Delphi Anda dapat menelan PDF berskala gigabyte dengan mudah, sehingga meningkatkan kinerja dan skalabilitas secara dramatis.
Catatan: Penanganan aliran I/O yang dioptimalkan untuk dokumen besar dibangun secara langsung ke dalam Komponen VCL HotPDF.