使用 Spring webServiceTemplate 和 jaxb 库会导致 «java.lang.ref.Finalizer» 的内存泄漏
Posted
技术标签:
【中文标题】使用 Spring webServiceTemplate 和 jaxb 库会导致 «java.lang.ref.Finalizer» 的内存泄漏【英文标题】:Using Spring webServiceTemplate and jaxb library leads to memory leak with «java.lang.ref.Finalizer» 【发布时间】:2021-12-13 10:40:14 【问题描述】:我正在我的多线程应用程序(10 个线程)中执行 webServiceTemplate.marshalSendAndReceive,它会导致 Finalizer 类发生内存泄漏。我发现在调试时哪些类在其实现中使用了 finalize。在大多数情况下,它是 UnmarshallerImpl 和 HttpsURLConnectionImpl。 Jaxb2Marshaller 为每个请求创建 UnmarshallerImpl 的新实例,并且我发现,GC 无法删除这些对象,直到低优先级线程为每个实例执行 finalize()。 显然,FinalizerThread 无法及时处理这个对象的queuq,也没有释放内存。当我模拟调用 webServiceTemplate.marshalSendAndReceive 的方法时,内存泄漏问题消失了。有没有办法解决这个问题?
这是我的 WebServise 配置:
@Configuration
public class WebServiceConfig
private final Props props;
private final ApplicationProps applicationProps;
public WebServiceConfig(@NotNull final Props props, @NotNull final ApplicationProps applicationProps)
this.props = props;
this.applicationProps = applicationProps;
@Bean
public Jaxb2Marshaller marshaller()
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setPackagesToScan(applicationProps.getPackagesToScan());
return marshaller;
@Bean
public WebServiceTemplate webServiceTemplate(final WebServiceTemplateBuilder builder, final AllTimeouts allTimeouts)
return builder
.setMarshaller(marshaller())
.setUnmarshaller(marshaller())
.messageSenders(new BasicAuthHttpsConnectionMessageSender(
props.getUsername(),
props.getPassword(),
allTimeouts.getReadTimeout()))
.build();
public class BasicAuthHttpsConnectionMessageSender extends HttpsUrlConnectionMessageSender
private final String b64Creds;
public BasicAuthHttpsConnectionMessageSender(final String username,
final String password,
final Integer readTimeout)
byte[] message;
message = String.format("%s:%s", username, password).getBytes(StandardCharsets.UTF_8);
b64Creds = DatatypeConverter.printBase64Binary(message);
setReadTimeout(Duration.ofMillis(readTimeout));
@Override
protected void prepareConnection(final HttpURLConnection connection) throws IOException
connection.setRequestProperty(HttpHeaders.AUTHORIZATION, String.format("Basic %s", b64Creds));
super.prepareConnection(connection);
这是我的依赖:
dependencies
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-web-services'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'
implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
implementation group: 'net.logstash.logback', name: 'logstash-logback-encoder', version: '4.10'
compile('javax.xml.bind:jaxb-api:2.3.0')
compile('javax.activation:activation:1.1')
compile('org.glassfish.jaxb:jaxb-runtime:2.3.0')
compile 'org.hibernate.validator:hibernate-validator:6.0.13.Final'
compile group: 'org.postgresql', name: 'postgresql', version: '42.2.11'
compile group: 'org.springframework.vault', name: 'spring-vault-core', version: '2.1.3.RELEASE'
compile group: 'org.springframework.ws', name: 'spring-ws-security', version: '2.2.2.RELEASE'
compile group: 'org.springframework.ws', name: 'spring-ws-support', version: '2.2.2.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version: '2.1.8.RELEASE'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
【问题讨论】:
【参考方案1】:请考虑将 webServiceTemplate(...)
中对 marshaller()
的调用替换为 Spring 注入的 bean:
@Bean
public WebServiceTemplate webServiceTemplate(
final WebServiceTemplateBuilder builder,
final AllTimeouts allTimeouts,
final Jaxb2Marshaller marshaller)
否则,对webServiceTemplate
的调用会导致创建新的编组器,跳过您的工厂方法Jaxb2Marshaller marshaller()
。
【讨论】:
【参考方案2】:虽然 finalize() 方法在 Java 9 之后被弃用了,但是 jaxb 库仍然使用 finalize。所以如果我们使用 jaxb 就会发生内存泄漏。您可以通过this 了解更多信息。
【讨论】:
以上是关于使用 Spring webServiceTemplate 和 jaxb 库会导致 «java.lang.ref.Finalizer» 的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
转Spring的WebServiceTemplate访问WebService的方法及其本质原理
Spring WS WebServiceTemplate:访问响应的内容或自定义unmarshaller
使用 HttpComponentsMessageSender 的具有基本身份验证的 WebServiceTemplate
使用 SOAP Web 服务错误(未注册编组器。检查 WebServiceTemplate 的配置)
Java笔记-解决WebServiceTemplate中No subject alternative names matching IP address xxx