You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何XSLT代码导致Saxonc崩溃?循环调用偶发故障排查

问题描述

循环中连续调用自定义的xslt.transform()方法约3次时,有50%概率崩溃无法完成循环。首次执行通常正常,怀疑是循环间未重置new_xslt30_processor或PySaxonProcessor,资源未清理导致。

报错信息

JET RUNTIME HAS DETECTED UNRECOVERABLE ERROR: runtime error Thread C8B63 ["Thread-0"] is terminated without notifying the JVM. Probably, "DetachCurrentThread" function was not called Please, contact the vendor of the application. Core dump will be piped to "/lib/systemd/systemd-coredump %P %u %g %s %t 9223372036854775808 %h" Extra information about error is saved in the "jet_err_822032.txt" file.

代码(xslt.py)

import os
import saxonc

from typing import Dict, List

class Xslt():

  @classmethod
  def transform(cls, xsl_file: str, xml_file: str, output_file: str, parameters: Dict[str,str]) -> bool:
    try:
      out = cls.transform_to_string(xsl_file, xml_file, parameters)
      with open(output_file, "w") as f:
        f.write(out)
      return True
    except Exception as e:
      print(str(e))
      return False

  @classmethod
  def transform_to_string(cls, xsl_file: str, xml_file: str, parameters: Dict[str,str]) -> str:
    with saxonc.PySaxonProcessor(license=True) as saxonproc:
      xsltproc = saxonproc.new_xslt30_processor()
      for parameter in parameters:
        xsltproc.set_parameter(parameter, saxonproc.make_string_value(parameters[parameter]))
      saxonproc.set_cwd(os.getcwd())
      return xsltproc.transform_to_string(source_file=xml_file, stylesheet_file=xsl_file)

运行输出

Error: failed to allocate an object - please check if an exception was thrown proc is nullptr in SaxonProcessor constructor Error: failed to allocate an object - please check if an exception was thrown Error: failed to allocate an object - please check if an exception was thrown Error: failed to allocate an object - please check if an exception was thrown Error: Xslt30Processor not in a clean state. - Exception found

╭─ bash   SaxonHE11-4J  羽393ms⠀                                                   11.0.16     toddmo  104.5.65.251
╰─ff java -cp saxon-he-11.4.jar net.sf.saxon.Version
SAXON-J-HE 11.4 from Saxonica (build 72811)

解决方案

你的推测完全正确:循环中频繁创建PySaxonProcessor实例会导致JNI线程资源泄漏,触发JET运行时的线程未分离错误。核心解决思路是复用处理器实例,而非每次调用都重新创建。

1. 修改类结构,复用处理器实例

将处理器实例移至类属性,初始化一次后重复使用,避免重复创建JNI资源:

import os
import saxonc
from typing import Dict, List

class Xslt():
    # 类级别的处理器实例,仅初始化一次
    _saxonproc = None
    _xsltproc = None

    @classmethod
    def init(cls):
        """初始化处理器,在循环执行前调用一次"""
        if cls._saxonproc is None:
            cls._saxonproc = saxonc.PySaxonProcessor(license=True)
            cls._xsltproc = cls._saxonproc.new_xslt30_processor()
            cls._saxonproc.set_cwd(os.getcwd())

    @classmethod
    def cleanup(cls):
        """手动清理资源,循环结束后调用"""
        if cls._saxonproc is not None:
            cls._saxonproc.close()
            cls._saxonproc = None
            cls._xsltproc = None

    @classmethod
    def transform(cls, xsl_file: str, xml_file: str, output_file: str, parameters: Dict[str,str]) -> bool:
        try:
            out = cls.transform_to_string(xsl_file, xml_file, parameters)
            with open(output_file, "w") as f:
                f.write(out)
            return True
        except Exception as e:
            print(str(e))
            return False

    @classmethod
    def transform_to_string(cls, xsl_file: str, xml_file: str, parameters: Dict[str,str]) -> str:
        # 确保处理器已初始化
        if cls._xsltproc is None:
            raise RuntimeError("请先调用Xslt.init()初始化处理器")
        
        # 关键:每次调用前清空旧参数,避免状态污染
        cls._xsltproc.clear_parameters()
        for param_name, param_value in parameters.items():
            cls._xsltproc.set_parameter(param_name, cls._saxonproc.make_string_value(param_value))
        
        return cls._xsltproc.transform_to_string(source_file=xml_file, stylesheet_file=xsl_file)

2. 正确使用方式

在循环前初始化处理器,循环结束后手动清理:

# 初始化处理器
Xslt.init()

# 循环执行转换任务
for task in your_task_list:
    Xslt.transform(task.xsl_path, task.xml_path, task.output_path, task.params)

# 循环结束后释放资源
Xslt.cleanup()

3. 关键注意事项

  • 每次调用转换方法前必须调用clear_parameters(),否则会因参数残留触发Xslt30Processor not in a clean state错误
  • 处理器实例必须在循环外初始化,避免重复创建JNI线程导致资源泄漏
  • 循环结束后必须调用cleanup(),确保JNI线程正常终止并释放资源

内容的提问来源于stack exchange,提问作者toddmo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 05:10:20