HotXLS는 워크시트 셀을 컴팩트한 256행 블록으로 저장하고, 행, 열, 사각형 서식을 셀 객체를 만드는 대신 지연 인터벌 오버레이로 해결하며, 저장 시 각 행을 패키지 deflate 스트림으로 직접 스트리밍합니다. 이 세 가지 변화가 함께 대용량 통합 문서의 메모리 프로파일을 결정합니다. 피크 사용량은 전체 워크시트 XML의 크기가 아니라 가장 큰 단일 행을 따릅니다
이것이 중요한 이유는 모든 스프레드시트 개발자가 결국 만나는 형태 때문입니다. 사용자가 전체 열에 서식을 지정합니다. 한 번의 클릭, 백만 개의 셀이며, 단순한 객체 모델은 하나의 숫자 형식 인덱스를 담기 위해 백만 개의 셀 객체를 할당하는 것으로 대답합니다. 디스크의 파일은 XLSX 형식이 그것을 단일 <col> 항목으로 표현하므로 작게 유지됩니다. 프로세스는 전혀 작게 유지되지 않습니다
열을 채우는 것보다 서식 지정이 메모리를 더 많이 쓰는 이유는 무엇인가
서식이 객체를 정당화할 데이터가 없기 때문입니다. 값을 가진 셀은 어딘가에 존재해야 합니다. 비어 있으면서 스타일이 적용된 셀은 스타일 인덱스를 담기 위해서만 존재하며, 그런 것을 수백만 개 구체화하는 것이 Delphi 스프레드시트 애플리케이션이 Excel이 즉시 여는 파일에서 주소 공간을 다 써버리는 고전적인 방식입니다
인터벌 스타일 오버레이가 그 필요를 제거합니다. 행, 열, 사각형 서식 지정 명령은 범위와 그것이 기여하는 스타일 부분으로 한 번 저장되며, 그 범위의 셀이 실제로 접근될 때 지연 해석됩니다. 오버레이는 구조적 편집을 견뎌냅니다. 서식이 지정된 블록 안에 행을 삽입하면 인터벌을 다시 구축하는 대신 옮깁니다. 그리고 컴팩트한 열, 행, 스타일 전용 셀 항목으로 왕복하며, 이는 Excel이 기록하는 방식 그대로입니다
var
Sheet: TXLSXWorksheet;
State: TXLSXCellStyleState;
begin
Sheet := Workbook.Sheets[1];
// Style indexes come from the workbook style pools, e.g. from a cell
// you have already formatted the way you want the range to look
State := BuildStateFromTemplateCell(Sheet.Cells.Item[1, 1]);
// Format columns B..D without creating a single empty cell object
Sheet.StyleOverlays.Add(1, 2, MaxRowIndex, 4,
[xfpNumberFormat, xfpAlignment], State);
end;
TXLSXFormatParts가 오버레이가 무엇을 기여하는지 결정하는 집합입니다. xfpFont, xfpFill, xfpBorder, xfpNumberFormat, xfpAlignment, xfpProtection이 있습니다. 의도한 부분만 이름 짓는 것이 오버레이가 합리적으로 쌓이게 합니다. 숫자 형식을 공급하는 열 오버레이는 채우기를 공급하는 행 오버레이와 싸우지 않는데, 어느 쪽도 다른 쪽의 부분을 주장하지 않기 때문입니다
256행 블록이 주는 것
지역성입니다. 셀은 안정적인 공개 핸들과 함께 256행 블록으로 보관되며 행 우선으로 직렬화되어, 워크시트를 기록하는 것이 바이트를 내보낼 순서대로 메모리를 걷는 것이 되지 힙을 가로질러 포인터를 쫓는 것이 되지 않습니다. 안정적인 핸들은 API 표면에 중요합니다. 호출자가 쥔 핸들은 블록 레이아웃이 수행하는 내부 재조직을 가로질러 유효하게 남으며, 이것이 컴팩트한 표현을 호환성 깨는 변경이 아니라 구현 세부사항으로 만듭니다
스타일 풀 컴팩션이 그 옆에서 실행됩니다. 매 저장 전에 어떤 셀도 참조하지 않는 폰트, 채우기, 테두리, 숫자 형식, 정렬, 보호가 삭제됩니다. 오래 산 통합 문서는 오래 산 문서가 미사용 스타일을 축적하듯 참조되지 않는 스타일 레코드를 축적하며, 사용자가 한 시간 편집한 통합 문서는 아무도 읽지 않을 수백 개를 파일로 옮길 수 있습니다
행 스트리밍 저장, 그리고 적용되지 않을 때
StreamingWrite가 활성화된 상태, 즉 기본값에서는 각 워크시트 행이 패키지 deflate 스트림에 직접 기록됩니다. 플래그가 꺼지는 대안은 전체 워크시트 XML을 먼저 구성한 뒤 압축하므로, 피크 메모리가 전체 시트에 비례합니다. 스트리밍은 한 행에 비례하게 만듭니다
공유 문자열과 보조 파트는 한 번에 하나의 항목을 내보내는 재사용 가능한 UTF-8 직렬화기를 통해 같은 훈련을 따르며, 피크 메모리를 전체 파트가 아니라 가장 큰 단일 항목으로 제한합니다. 이것은 공유 문자열 테이블과 피벗 레코드를 커버하며, 넓은 분석 통합 문서에서는 개별 워크시트보다 자주 더 큽니다
var
Workbook: TXLSXWorkbook;
begin
Workbook := TXLSXWorkbook.Create(nil);
try
Workbook.Open('ledger-2026.xlsx');
// StreamingWrite defaults to True; turn it off only when a downstream
// step requires the whole worksheet XML to exist before compression
Workbook.StreamingWrite := True;
Workbook.SaveAs('ledger-2026-out.xlsx');
finally
Workbook.Free;
end;
end;
구체적인 이유가 없는 한 켜두십시오. 비스트리밍 경로는 파이프라인의 다른 무언가가 조립된 XML을 필요로 하는 사례를 위해 존재하며, 기본으로 그 비용을 치르는 것은 대부분의 애플리케이션이 결코 만나지 않는 사례에 대해 지불하는 것입니다
오버레이가 실제로 사용되고 있는지 어떻게 아는가
메모리 그래프가 아니라 셀 수를 보십시오. 넓은 서식을 적용한 후 워크시트가 그럴듯한 수의 물리적 셀을 보고하면 오버레이가 제 역할을 하는 것입니다. 수가 서식 지정 범위의 크기만큼 뛰면 코드 경로의 무언가가 셀을 구체화한 것입니다. 보통은 범위의 모든 셀을 읽어 스타일을 점검하는 루프이며, 이는 한 번에 하나씩 해석을 강제하여 전체 배치를 무력화합니다
한 셀의 유효 서식이 필요할 때 스타일을 해석하십시오. 열이 숫자 형식을 가지고 있다는 것을 알아내기 위해 백만 셀의 스타일을 해석하지 마십시오. 오버레이에 물어보십시오. 같은 규칙이 기록에 적용됩니다. 값을 가진 셀에 값을 할당하고, 서식이 인터벌로 남게 하십시오
나머지 메모리가 가는 곳
셀과 스타일이 컴팩트해진 뒤, 큰 통합 문서에서 다음으로 큰 소비자는 공유 문자열 테이블과 파일이 담은 위성 파트들, 즉 피벗 캐시, 드로잉, 객체 모델이 모델링하지 않는 파트에서 보존된 XML입니다. 그것들은 각자 자신의 전략을 가지며, 정직한 대답은 단일 설정이 그 모든 것을 한 번에 풀지 못한다는 것입니다
저장이 아니라 열기가 병목이라면 선택적 로딩이 레버입니다. 메타데이터 전용과 선택적 워크시트 로딩 산책문이 만지지 않을 시트에 대해 비용을 치르지 않고 통합 문서를 읽는 것을 다룹니다. 매우 큰 파일의 읽기 경로 처리량은 병렬 XLSX 파싱과 메모리 할당자에 관한 글을 보고, 객체 모델이 전혀 필요 없는 출력 전용 워크로드에는 서버 배치 작업을 위한 스트리밍 기록이 여기의 어떤 튜닝보다도 더 잘 맞는 경우가 많습니다
HotXLS는 Excel 설치와 OLE 자동화 없이 네이티브 Delphi와 C++Builder 코드로 XLS와 XLSX를 읽고 쓰며, 이것이 이런 메모리 특성을 관찰 가능하고 통제 가능하게 만듭니다. HotXLS 스프레드시트 컴포넌트 페이지에 지원 형식과 RAD Studio 버전이 나열되어 있습니다