У нас есть книга Excel, которая довольно большая.Около 3300 столбцов и несколько тысяч строк.
Мы обнаружили, что попытка что-либо сделать с данными приводит к высокому использованию памяти, около 3 ГБ.
Похоже, что пакет DocumentFormat.OpenXml
при повторении сохраняет полную структуру объекта рабочего листа в памяти.Как правило, мы делаем это:
var workbookPart = _document.WorkbookPart;
var worksheets = workbookPart.Workbook.Descendants<Sheet>();
foreach(var worksheet in worksheets)
{
var worksheetPart = (WorksheetPart) workbookPart.GetPartById(worksheet.Id);
foreach(var row in worksheetPart.Worksheet.Descendants<Row>())
{
foreach(var cell in row.Descendants<Cell>())
{
var (_, value) = ParseCell(cell);
}
}
}
ParseCell
просто получает содержимое Cell
, просматривая строковое значение из SharedStringTable
в книге или, если это число,парсинг числа.
Простой запуск этого кода, который ничего не делает с результатом ParseCell
, все еще использует значительную память.
Когда мы профилировали этот код, мы заметили, что существует Cell
в куче для каждой ячейки на листе, несмотря на все наши попытки использовать API IEnumerable<T>
, чтобы исключить наличие больших коллекций в памяти.
Это довольно близко к рекомендованному использованию этого пакета Nuget.
Из профилирования появляется проблема в том, что каждый Cell
имеет сильную ссылку на следующий Cell
, и аналогично для Row
.
Каждый Cell
имеетполе с именем и _next
, которое удерживает каждую ячейку с сильным корнем.Ячейка A имеет сильную ссылку на ячейку B, B на C, C на D.
Row
имеет аналогичную структуру, где строка 0 имеет поле _next
для строки 1, и так далее, и так далееТаким образом, для каждого Row
, через который мы проходим, он строго ссылается на следующий Row
.
Так что все связаны друг с другом.Когда я посмотрел на это с помощью WinDbg после того, как он обработал последние 10 * 10, в куче было ровно столько Cell
с от !dumpheap -stat
, сколько содержится в книге.
То, как мы используемэтот SDK не будет масштабироваться до большего количества строк.Есть ли способ более эффективно использовать этот пакет и обрабатывать рабочую таблицу построчно, не сохраняя в памяти граф объектов всего рабочего листа?