Стратегия iText7 для ограничения потребления памяти PdfFont

большинство примеров iText7 относятся к использованию PdfFontFactory.createFont() для получения дескрипторов экземпляров PdfFont для текстовых операций. С модерацией это нормально ... но PdfFont - довольно тяжелый объект (PdfEncoding), который, похоже, не исчезнет, ​​пока PdfDocument не будет закрыт. Итак, следующий невинный блок поглотит память:

for (int i = 0; i < someLargeNumber; i++) {
    list.add(
        new ListItem("never gonna give")
        .setFont(PdfFontFactory.createFont("Helvetica-Oblique"))
    )
}

тривиальная попытка решения с использованием статики не удалась, поскольку кажется, что экземпляры PdfFont нельзя использовать более чем в одном документе PdfDocument. И поскольку мой реальный случай более сложен, чем приведенный выше пример, я не хочу передавать кучу ссылок PdfFont через довольно глубокий стек.

  1. в API iText7 нет возможности перебирать существующие PdfFont для PdfDocument (есть ли?)
  2. является правилом использования PdfFont просто: а) его можно использовать сколько угодно раз; б) в одном экземпляре PdfDocument

(т.е. можно ли здесь просто кэшировать экземпляры PdfFont с помощью ключа PdfDocument + PdfFontProgram?)


person jamey graham    schedule 26.07.2016    source источник
comment
предложенный выше cacheKey - плохая идея. Похоже, что экземпляры FontProgram кэшируются в статической карте, что означает, что ключ кеша weakRef всегда будет использоваться (и в результате PdfDocument также будет храниться в памяти). Кажется, что лучшим подходом будет карта карт - WeakHashMap ‹PdfDocument, Map‹ String, PdfFont ››   -  person jamey graham    schedule 28.07.2016


Ответы (1)


PdfFonts кажутся кэшируемыми / повторно используемыми на уровне PdfDocument. Если в качестве кеша используется WeakHashMap, ключи и значения должны быть слабыми ссылками. Например

private static WeakHashMap<PdfDocument, Map<String, WeakReference<PdfFont>>> fontCache = new WeakHashMap<>();

public static synchronized PdfFont createFont(PdfDocument forDocument, String path) throws IOException {
    Map<String, WeakReference<PdfFont>> documentFontMap = fontCache.get(forDocument);
    if (documentFontMap == null) {
        documentFontMap = new HashMap<>();
        fontCache.put(forDocument, documentFontMap);
    }
    WeakReference<PdfFont> font = documentFontMap.get(path);
    if (font == null) {
        font = new WeakReference<>(PdfFontFactory.createFont(path));
        documentFontMap.put(path, font);
    }
    return font.get();
}

Также следует позаботиться о iText API, который вызывает сам PdfFontFactory, например, производных от Barcode1D, настроенных для отображения удобочитаемого значения (т.е. создание нового экземпляра Barcode1D на страницу без вызова setFont () быстро исчерпает память для больших документов)

person jamey graham    schedule 11.08.2016