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

使用Spring WebServiceTemplate与JAXB出现Finalizer内存泄漏如何解决

解决方案

1. 复用Unmarshaller实例,避免频繁创建新对象

默认Jaxb2Marshaller每次请求都会新建Unmarshaller实例,而Unmarshaller是非线程安全的,可以通过ThreadLocal缓存每个线程的实例,大幅减少对象创建销毁次数:

public class PooledJaxb2Marshaller extends Jaxb2Marshaller {
    private final ThreadLocal<Unmarshaller> unmarshallerThreadLocal = ThreadLocal.withInitial(() -> {
        try {
            return super.createUnmarshaller();
        } catch (JAXBException e) {
            throw new RuntimeException("创建Unmarshaller失败", e);
        }
    });

    @Override
    public Object unmarshal(Source source) throws XmlMappingException {
        Unmarshaller unmarshaller = unmarshallerThreadLocal.get();
        try {
            return unmarshaller.unmarshal(source);
        } catch (JAXBException e) {
            throw convertJaxbException(e);
        }
    }
}

修改WebServiceConfig中的marshaller Bean定义,使用自定义的PooledJaxb2Marshaller即可。

2. 替换HTTP消息发送器,消除HttpsURLConnectionImpl实例堆积

默认的HttpsUrlConnectionMessageSender基于JDK原生HttpURLConnection实现,连接实例销毁时会触发finalize方法。可以改用池化的Apache HttpComponents实现,从根源减少连接实例的创建:
首先新增依赖:

// 请根据你的Spring Boot版本选择匹配的版本号
implementation 'org.springframework.ws:spring-ws-support:2.4.7.RELEASE'
implementation 'org.apache.httpcomponents:httpclient:4.5.14'

修改消息发送器配置:

@Bean
public HttpComponentsMessageSender httpComponentsMessageSender(Props props, AllTimeouts allTimeouts) {
    // 配置连接池
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
    connectionManager.setMaxTotal(20); // 按实际并发量调整
    connectionManager.setDefaultMaxPerRoute(10);
    // 配置基础认证
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY,
            new UsernamePasswordCredentials(props.getUsername(), props.getPassword()));
    // 构建HttpClient
    HttpClient httpClient = HttpClientBuilder.create()
            .setConnectionManager(connectionManager)
            .setDefaultCredentialsProvider(credentialsProvider)
            .setDefaultSocketTimeout(allTimeouts.getReadTimeout())
            .build();
    return new HttpComponentsMessageSender(httpClient);
}

最后修改webServiceTemplate的messageSenders配置,替换为上述自定义的httpComponentsMessageSender即可。

3. 升级JAXB运行时版本,移除finalize逻辑

你当前使用的2.3.0版本的jaxb-runtime中,UnmarshallerImpl实现了finalize方法,2.3.2及以上版本已经移除了该方法,直接升级依赖即可解决该类的Finalizer队列堆积问题:

implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation 'org.glassfish.jaxb:jaxb-runtime:2.3.6'
// 可移除原来单独引入的activation依赖,新版jaxb-runtime已内置

4. 应急JVM调优方案(仅临时使用,不推荐长期生效)

如果暂时无法修改代码,可以通过JVM参数加快Finalizer队列处理速度:

  • 调高Finalizer线程优先级:-XX:FinalizerPriority=10
  • 改用低延迟垃圾回收器(如ZGC/Shenandoah),提升Finalizer队列处理效率

验证方式

修改完成后执行压测,通过jmap -histo:live <pid>查看Finalizer对象数量,或导出堆dump确认是否还有大量UnmarshallerImpl、HttpsURLConnectionImpl实例堆积。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:09:02