Куча JVM, содержащая преобразованные объекты, интенсивно использующие память, после выполнения преобразования xslt с использованием библиотек Saxon 9.6 HE - PullRequest
0 голосов
/ 07 октября 2019

Краткое описание проблемы: При добавлении значений в hashmap после преобразования xslt в шаблоны с использованием библиотеки saxon 9.6 HE выделение кучи увеличивается до 330 МБ, что составляет почти 70% кучи (Xmx512 и Xms32). Когда в корзину добавляется больше товаров, она набирает 512 баллов и уходит в OOM, генерируя файлы phd и javacore.

Что мы пробовали: Когда мы использовали версию Saxon 9.9 HE, она экономила около 30 МБ вобщая куча, но она все еще находится на уровне 300 МБ

Цель:

1) Goal is to reduce the memory footprint. 
2) Is there any fine tuning as per saxon libraries to reduce this huge heap for the transformed objects
3) We wouldn't want to remove those hashmaps from memory as those templates are needed for faster printing at the end of a cart transaction (like in a point of sale system) - hence we haven't used the getUnderlyingController.clearDocumentPool() in saxon;

Детали кода:

Саксонская инициализация в конструкторе

package com.device.jpos.posprinter.receipts;
import java.util.HashMap;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import net.sf.saxon.TransformerFactoryImpl;

import com.device.jpos.posprinter.receipts.saxon.SaxonFunctions;
public class ReceiptXSLTTemplateManager
{

   private HashMap<String, String>    xsltTemplates      = null;
   private HashMap<String, Templates> xsltTransTemplates = null;
   private TransformerFactory         transformerFact    = null;
   public ReceiptXSLTTemplateManager( String xsltProcessor )
   {
      this.xsltProcessor = xsltProcessor;
      setTransformerFactory();
      xsltTemplates = new HashMap<String, String>();
      xsltTransTemplates = new HashMap<String, Templates>();
      // create an instance of TransformerFactory
      transformerFact = javax.xml.transform.TransformerFactory.newInstance();
      if ( transformerFact instanceof TransformerFactoryImpl )
      {
         TransformerFactoryImpl tFactoryImpl = (TransformerFactoryImpl) transformerFact;
         net.sf.saxon.Configuration saxonConfig = tFactoryImpl.getConfiguration();
         SaxonFunctions.register( saxonConfig );
      }
    }
}

Преобразование xslt и добавление в hashmap

 public boolean setTransformer( String name )
   {
      if ( xsltTemplates.containsKey( name ) )
      {
         StringReader xsltReader = new StringReader( xsltTemplates.get( name ) );
         javax.xml.transform.Source xsltSource = new javax.xml.transform.stream.StreamSource( xsltReader );

         try
         {
            Templates transTmpl = transformerFact.newTemplates( xsltSource );
            xsltTransTemplates.put( name, transTmpl );
            return true;
         }
         catch ( TransformerConfigurationException e )
         {
            logger.error( String.format( "Error creating XSLT transformer for receipt type = %s.", name ) );
         }

      }
      else
      {
         logger.error( String.format( "Error creating XSLT transformer for receipt type = %s.", name ) );
      }

      return false;
   }

Итак, хотя шаблоны xsl имеют размердиапазон от 200 КБ до 500 КБ, при преобразовании их объем в памяти составляет от 5 до 15 МБ. У нас есть 45 таких файлов, и в целом это потребляет почти 70% кучи JVM. В сочетании с другими операциями, которые используют память кучи, результатом является ошибка OutOfMemory от JVM.

Выход анализатора памяти из файла phd (ссылка на изображение):

Анализатор памяти, отображающий записи хеш-карты и преобразование s9api

Выход анализатора памяти из файла phd (ссылка на изображение)

Детализированные записи хэш-карты (изображениессылка)

У нас есть следующие вопросы: 1) Почему шаблон размером от 200 КБ до 500 КБ на диске занимает от 5 МБ до 15 МБ в памяти? после трансформации? 2) Что можно оптимизировать в том, как создаются шаблоны, прежде чем помещать их в hashmap с помощью saxon 9.6 HE или мы должны использовать другие выпуски saxon особым образом, чтобы преодолеть эту проблему с памятью.

Пожалуйста, сообщите. Спасибо за ваше драгоценное время !!

1 Ответ

0 голосов
/ 08 октября 2019

Заполнение памяти скомпилированными таблицами стилей никогда не было чем-то, что мы серьезно рассматривали или рассматривали как проблему - за исключением, возможно, генерации байт-кода, которую мы сейчас делаем «по требованию», чтобы предотвратить худшие излишки. В центре внимания всегда была максимальная скорость выполнения, и это означает создание некоторых довольно сложных структур данных, например таблиц решений для поддержки сопоставления шаблонных правил. Также имеется немало данных, сохраняемых исключительно для обеспечения хорошей диагностики во время выполнения.

В прошлом мы предпринимали усилия, чтобы гарантировать, что фактическое дерево таблиц стилей может быть собрано после сборки, ноЯ знал, что теперь в дереве есть ссылки, которые предотвращают это. Я не уверен, насколько важен этот фактор.

Если вы работали с Saxon-EE, вы могли бы поэкспериментировать с экспортом и повторным импортом скомпилированной таблицы стилей. Это вытеснит ссылки на структуры данных, используемые только временно во время компиляции, что может сэкономить некоторую память.

Кроме того, Saxon-EE выполняет JIT-компиляцию правил шаблона, поэтому, если существует много правил шаблона, которые никогда не вызываютсяпоскольку вы используете только небольшую часть большого словаря XML, это даст экономию памяти.

Если ваши 45 таблиц стилей имеют перекрывающееся содержимое, то было бы полезно переместить эти общие компоненты в отдельно скомпилированные пакеты XSLT 3.0.

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

Между тем я зарегистрировал проблему на https://saxonica.plan.io/issues/4335 в качестве напоминания, чтобы посмотреть на это в следующий раз, когда мы получим шанс.

...