Memory leak, spring 3.2.0.RELEASE, httpcomponents 4.2.3

Using spring 3.2.0.RELEASE resttemplate and httpcomponents 4.2.3 for call forwarding. The memory capacity is constantly increasing until it reaches the maximum.

Below is the configuration:

<bean id="myRestTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>
        <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
            <constructor-arg index="0">
                <bean factory-bean="httpClient" factory-method="get"/>
            </constructor-arg>
        </bean>
    </constructor-arg>
</bean>
<bean id="httpClient" class="com.mycompany.myproject.common.rest.HttpClient">
    <constructor-arg index="0" ref="myKeyserverCA" ></constructor-arg>
    <constructor-arg index="1" value="${com.mycompany.myproject.security.client.keyPassword}" ></constructor-arg>
    <constructor-arg index="2" value="${default.max.total.connections}" ></constructor-arg>
    <constructor-arg index="3" value="${default.max.host.connections}" ></constructor-arg>
</bean>
<bean id="myKeyserverCA"
      class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
    <property name="location" value="classpath:${com.mycompany.myproject.security.client.keyStore}" />
    <property name="password" value="${com.mycompany.myproject.security.client.keyStorePass}" />
</bean>    

      

HttpClient:

import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.CoreConnectionPNames;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.security.KeyStore;

public class HttpClient {

private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);

private KeyStore keystore;
private String password;
private int MAX_TOTAL_CONNECTION;
private int MAX_PER_ROUTE;

public HttpClient(KeyStore keyStore, String keyPassword, int MAX_TOTAL_CONNECTION, int MAX_PER_ROUTE) {
    this.keystore = keyStore;
    this.password = keyPassword;
    this.MAX_TOTAL_CONNECTION = MAX_TOTAL_CONNECTION;
    this.MAX_PER_ROUTE = MAX_PER_ROUTE;
}

public org.apache.http.client.HttpClient get() {
    PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(getSchemeRegistry(this.keystore, this.password));
    connectionManager.setMaxTotal(MAX_TOTAL_CONNECTION);
    connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE);
    connectionManager.closeExpiredConnections();

    org.apache.http.client.HttpClient httpClient = new DefaultHttpClient(connectionManager);
    httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, DEFAULT_READ_TIMEOUT_MILLISECONDS);
    return httpClient;
}

private static SchemeRegistry getSchemeRegistry(KeyStore keyStore, String keyPassword) {
    SchemeRegistry registry = new SchemeRegistry();
    try{
        TrustManager[] trustManagerArray = { new TautologicalX509TrustManager() };
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, keyPassword.toCharArray());

        SSLContext sslc = SSLContext.getInstance("TLS");
        sslc.init(kmf.getKeyManagers(), trustManagerArray, null);
                    SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslc, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                    registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
        registry.register(new Scheme("https", 443, sslSocketFactory));
        return registry;
    }catch(Exception e){
        throw new RuntimeException(e.getMessage());
    }
}
}    

      

TautologicalX509TrustManager:

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class TautologicalX509TrustManager  implements X509TrustManager {

private static final X509Certificate[] EMPTY_CERTIFICATES = new X509Certificate [0];

public void checkClientTrusted(X509Certificate[] arg0, String arg1)
    throws CertificateException {
}

public void checkServerTrusted(X509Certificate[] arg0, String arg1)
        throws CertificateException {
}

public X509Certificate[] getAcceptedIssuers() {
    return EMPTY_CERTIFICATES;
}



}    

      

After running load tests on this component, we see a lot of SSLSocketImpl objects and bytes []. Inbound references to SSLSocketImpl are in the Finalizer object.

When we do netstat on the machine after stopping the load test, we don't see any open tcp connections to the underlying services. However, during the load test, there are many connections in the TIME_WAIT state and several in the ESTABLISHED state, but all are closed after the test is stopped.

Are we missing some API call to close the sockets? Why do we have so many SSLSocketImpl objects hanging in our heap?

+1


a source to share


1 answer


Bit late to answer, but this answer is for future visitors to this question. The reason you see a lot of space SSLSocketImpl

in your heap and then that gets garbage collected is because it SSLSessionContext

supports caching SSL connections that can be reused across different TCP connections to reduce handshake overhead when negotiating temporary encryption keys after an actual TCP connection is established.

The default is SSLSessionContext

unlimited sessions for a standard 24 hour time frame, which means you can use a lot of heap memory under high traffic. One way is to set the cache size to suit the needs of your application. Here's an example:



sslContext.getServerSessionContext().setSessionCacheSize(1000);

0


a source







All Articles