Olá,
Uma dúvida sobre consumo de memória RAM, tenho uma rotina que faz mesclagem de documentos pdf, em algum momentos pode ocorrer conversão de algum outro tipo para pdf antes, percebo que existe um aumento significativo de memória e quando todo o processo termina, essa memória fica alocada, todos os lugares que posso usar eu como USING, analisando o código não encontrei nada que poderia deixar alocado, é um comportamento da biblioteca mesmo?
Olá,
O aumento no consumo de memória durante a mesclagem de documentos PDF pode ser um comportamento esperado, especialmente se você estiver convertendo outros tipos de documentos para PDF antes da mesclagem. A biblioteca pode alocar memória para processar esses documentos temporariamente, e em alguns casos, essa memória pode não ser liberada imediatamente após a conclusão do processo.
Aqui estão algumas sugestões para otimizar o uso de memória:
-
Gerenciamento de Recursos: Certifique-se de que todos os objetos que você cria durante o processo estão sendo descartados corretamente. Utilize a instrução
usingpara garantir que os recursos sejam liberados assim que não forem mais necessários. -
Otimização de Desempenho: Verifique se você está utilizando as melhores práticas de otimização de desempenho disponíveis na biblioteca. Isso pode incluir a limitação do número de threads ou a personalização de filtros de pré-processamento de imagem.
-
Monitoramento de Memória: Utilize ferramentas de monitoramento de memória para identificar se há vazamentos ou se a memória está sendo utilizada de forma ineficiente.
Se o problema persistir, pode ser útil consultar a documentação sobre otimização de desempenho ou discutir no fórum da Aspose para obter insights adicionais.
Espero que isso ajude!
Poderia compactar e anexar o(s) documento(s) de amostra e também compartilhar seu código de exemplo aqui para nos ajudar a reproduzir o problema de consumo de memória? Revisaremos o problema rapidamente e forneceremos a assistência necessária em breve.
Olá, pessoal!
Estou trabalhando em uma funcionalidade em C#, .net8 que precisa juntar um grande volume de arquivos em um único PDF. Estamos falando de um cenário com mais de 500 arquivos que, no final, geram um documento com mais de 15.000 páginas.
O processo funciona, mas estou enfrentando um problema sério de consumo de memória RAM. Durante a execução, o consumo de memória sobe bastante (o que é esperado até certo ponto), mas o problema principal é que essa memória não é liberada mesmo após o método ser concluído e todos os objetos, teoricamente, saírem de escopo. O processo no gerenciador de tarefas continua com a memória alocada.
Abaixo está uma versão simplificada e com nomes genéricos do código que estou usando. A lógica é iterar sobre as páginas de um documento principal e, nos locais corretos, inserir as páginas dos documentos anexos em um novo documento.
// Método principal que orquestra a junção dos documentos
public void MergeDocuments(MergeDocumentRequest mergeRequest)
{
// … inicialização de variáveis como caminho do PDF principal e destino final …
using (PdfDocument finalDocument = new())
{
using (PdfDocument mainDocument = new(mainPdfPath))
{
// Obtém uma lista ordenada de onde cada anexo deve ser inserido
List<AttachmentReference> attachmentsToInsert = GetAttachmentReferences(mainDocument, mainFileInfo.FileName ?? string.Empty, mergeRequest)
.OrderBy(x => x.PageNumber)
.ThenBy(x => x.Order)
.ToList();
_logger.LogInformation("Iniciando processamento de {TotalAttachments} anexos.", attachmentsToInsert.Count);
// Itera sobre as páginas do documento principal
for (int pageNumber = 1; pageNumber <= mainDocument.Pages.Count; pageNumber++)
{
// Adiciona a página do documento principal ao documento final
finalDocument.Pages.Add(mainDocument.Pages[pageNumber]);
// Verifica se há anexos para inserir após esta página
if (attachmentsToInsert.Any(x => x.PageNumber == pageNumber))
{
foreach (AttachmentReference? reference in attachmentsToInsert.Where(x => x.PageNumber == pageNumber))
{
// Processa e insere as páginas do anexo
ProcessAndInsertAttachment(reference, mergeRequest, finalDocument);
}
}
}
}
// Se necessário, aplica numeração de página no documento final
if (mergeRequest.IncludePageNumbers)
{
ApplyFinalPagination(finalDocument, mergeRequest);
}
// Salva o arquivo PDF gigante
finalDocument.Save(finalDestinationPath);
}
// Neste ponto, eu esperava que a memória fosse liberada, mas não é.
}
// Método responsável por processar cada anexo individualmente
private void ProcessAndInsertAttachment(AttachmentReference reference, MergeDocumentRequest mergeRequest, PdfDocument finalDocument)
{
FileMetadata attachmentInfo = mergeRequest.FilesToMerge.First(f => f.FileName == reference.FileName);
List tempAttachmentFiles = [];
try
{
// Baixa o arquivo de anexo para uma pasta temporária local
string localAttachmentPath = Path.Combine(_localTempFolder, attachmentInfo.FileName!);
_storageService.DownloadFile(mergeRequest.Settings, attachmentInfo, _localTempFolder);
tempAttachmentFiles.Add(localAttachmentPath);
// Converte o anexo para PDF, se não for um (ex: DOCX, PNG -> PDF)
string attachmentPdfPath = ConvertFileToPdf(localAttachmentPath);
if (attachmentPdfPath != localAttachmentPath)
{
tempAttachmentFiles.Add(attachmentPdfPath);
}
if (File.Exists(attachmentPdfPath))
{
// Abre o anexo (já em formato PDF)
using (PdfDocument attachmentDocument = new(attachmentPdfPath))
{
// Adiciona todas as páginas do anexo ao documento final
for (int i = 1; i <= attachmentDocument.Pages.Count; i++)
{
finalDocument.Pages.Add(attachmentDocument.Pages[i]);
}
}
}
}
finally
{
// Garante que todos os arquivos temporários criados sejam removidos
foreach (string path in tempAttachmentFiles)
{
DeleteLocalFileSilently(path);
}
}
}
O código de exemplo é uma representação fiel da lógica. Na implementação real, garanto que todos os objetos que implementam IDisposable (como os documentos PDF) estão devidamente encapsulados em blocos using {}.
Não estou utilizando MemoryStream em nenhum ponto do processo; toda a manipulação é feita com base nos caminhos dos arquivos no disco.
Infelizmente, não posso compartilhar os PDFs utilizados, pois são documentos sensíveis e variados (diferentes tamanhos, versões e quantidades de páginas).
Uma observação crucial que fiz foi a seguinte: se eu executo o processo uma vez, a memória sobe para, digamos, 2,5 ~3Gb e fica presa nesse patamar. Se eu rodo o mesmo processo novamente em sequência, o consumo de memória primeiro cai 1.2 ~ 1.8Gb (provavelmente o GC sendo forçado a agir pela nova demanda mesmo assim considero alto, pensando que isso deveria cair para alguns poucos Mb) e depois sobe novamente até os mesmos 2,5 ~3Gb, isso são médias.
Isso me leva a crer que talvez não seja um “vazamento” clássico de memória não gerenciada, mas sim que o Garbage Collector (GC) não está vendo a necessidade de liberar os objetos grandes (provavelmente da Geração 2) após o primeiro uso.
Minhas perguntas são:
-
Esse comportamento (memória sendo liberada apenas sob nova pressão) é esperado em aplicações .NET que manipulam objetos muito grandes? Há algo que eu possa fazer para “sugerir” ao GC uma limpeza mais agressiva após a conclusão da tarefa?
-
A forma como as páginas são adicionadas uma a uma (
finalDocument.Pages.Add(...)) poderia estar criando uma estrutura de objetos em memória que o GC tem dificuldade de coletar rapidamente, mesmo com oDispose()sendo chamado pelousing? -
Considerando o volume extremo (15.000+ páginas), existe uma abordagem fundamentalmente diferente ou de “baixo consumo de memória” para esse tipo de operação com bibliotecas de PDF? Talvez alguma forma de fazer o merge diretamente no disco, sem carregar representações completas dos documentos em memória?
Obrigado por compartilhar esses detalhes para nossa referência. Você pode confirmar se já tentou usar a versão mais recente da API, ou seja, a 25.10, que acabou de ser lançada? Se ainda estiver causando problemas relacionados à memória, seria possível compartilhar algumas capturas de tela do aumento de memória, bem como da memória que não é liberada após o processamento ser concluído? Isso nos ajudará a investigar o caso adequadamente. Além disso, por favor, compartilhe alguns documentos PDF de exemplo para nossa referência, para que possamos usá-los na análise do problema.
Estou trabalhando em alguns pontos de atenção, volto em breve com mais informações.
Claro, por favor, tome o seu tempo e compartilhe as informações conosco assim que as tiver reunido. Prosseguiremos conforme necessário.