0

I'm executing webServiceTemplate.marshalSendAndReceive in my multithreaded app (10 threads) and it leads memory leak with Finalizer class. I have found which classes uses finalize in its implementetion while debugging. In in most cases it is UnmarshallerImpl and HttpsURLConnectionImpl. Jaxb2Marshaller creates new instanse of UnmarshallerImpl for every request, and as I found out, GC can't delete this objects, until low priority thread execute finalize() for each instanse. Apparently, FinalizerThread can't process the queuq of this object in time and does not free memory. When I mock method which calls webServiceTemplate.marshalSendAndReceive the problem with memory leak goes away goes away. Is there way to solve this problem?

Here is my WebServise configuration:

@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);
    }
}

Here is my dependensies:

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'
}

enter image description here

SorryForAsking
  • 323
  • 2
  • 18

2 Answers2

2

Please consider replacing calls to marshaller() in webServiceTemplate(...) with Spring-injected beans:

    @Bean
    public WebServiceTemplate webServiceTemplate(
        final WebServiceTemplateBuilder builder,
        final AllTimeouts allTimeouts,
        final Jaxb2Marshaller marshaller) {

Otherwise, calls to webServiceTemplate lead to creation of new marshallers, skipping your factory method Jaxb2Marshaller marshaller().

Piotr M.
  • 21
  • 4
0

Although finalize() method is deprecated after Java 9 onward but jaxb library still uses finalize.So if we are using jaxb memory leak will happen. You can go though this to know more.

Aditya
  • 31
  • 2
  • Yes, and this is the problem. Do you know any alternative libraries that dont use finalize() method in theirs implementations as jaxb? – SorryForAsking Apr 17 '22 at 13:04