Reputation: 99
I have an application deployed to WebSphere 8.5 (the app is developed using java8/Spring 4) and every day I get many dump files, so I decided to analyze it using Eclipse Memory Analyzer and the result is:
The problem is I do not use axis for calling web service, I only use Jersy for Rest Web Services and The default jdk class SoapConnection for soap web services, here is some code examples: For Soap :
public String soapBind(List<ContextItem> dic, String serviceId, String urlWs, String applicationId) throws SOAPException, Exception {
try {
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection soapConnection = soapConnectionFactory.createConnection();
SOAPMessage msg = soapCall(dic, serviceId, applicationId); // Send SOAP Message to SOAP Server
String url = urlWs;
LOGGER.info("CALLING WS ....");
SOAPMessage soapResponse = soapConnection.call(msg, url);
// print SOAP Response
//soapResponse.writeTo(System.out);
ByteArrayOutputStream out = new ByteArrayOutputStream();
soapResponse.writeTo(out);
soapConnection.close();
String strMsg = new String(out.toByteArray());
LOGGER.info("Response SOAP Message: {}",strMsg);
return strMsg;
} catch (SOAPException ex) {
throw ex;
} catch (UnsupportedOperationException ex) {
throw ex;
} catch (Exception ex) {
throw ex;
}
}
For Rest :
Client client = Client.create();
WebResource webResource = client
.resource(urlFicheClientProf);
//
ServiceContext serviceContext = this.getServiceContext();
//
ObjectMapper mapper = new ObjectMapper();
ClientResponse response = webResource
.queryParam("customerId", radical)
.queryParam("serviceContext",
URLEncoder.encode(mapper.writeValueAsString(serviceContext),
"UTF-8"))
.post(ClientResponse.class);
I am wondering why the Axis.Client Out of memory has occurred and how can I fix it. If anyone could help me figure it out I would be very grateful .
Upvotes: 1
Views: 741
Reputation: 99
Using RestTemplate instead of SOAPConnection fixed the memory leaks :
final RestTemplate restTemplate = new RestTemplate();
final HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "text/xml");
final HttpEntity<String> request = new HttpEntity<>(message, headers);
final String result = restTemplate.postForObject(wsUrl, request, String.class);
return result;
Upvotes: 0
Reputation: 1501
Regarding your first question: Why does Apache Axis2 get used when you use the default JDK class SOAPConnection? The class SOAPConnection is actually just a part of an API that could have different implementations. In your case WebSphere provides an implementation of this API based on Apache Axis2, that's why you are seeing objects of those classes lingering. The SOAPConnection Javadocs state:
The SOAPConnection class is optional. Some implementations may not implement this interface in which case the call to SOAPConnectionFactory.newInstance() (see below) will throw an UnsupportedOperationException.
About the second part of your question, I have a hypothesis. In the Javadocs I could not find if a call to SOAPConnection.close() is mandatory, but usually resource classes with a close() method do require cleaning up or else they create memory or other resource leaks. Your code does call close(), however if an exception occurs somewhere before closing the connection, the execution would jump straight to catch (...) and the connection will not be cleaned up, thus creating a memory leak. Maybe this happens every time a SOAP call throws an exception and this leaked the memory you are observing.
You could solve this by using a try-resource-close pattern described here: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html Try the following change in your code.
Edit:
public String soapBind(List<ContextItem> dic, String serviceId, String urlWs, String applicationId) throws SOAPException, Exception {
try {
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
try (MySOAPConnection mySoapConnection = new MySOAPConnection(soapConnectionFactory)) {
SOAPConnection soapConnection = mySoapConnection.connection;
SOAPMessage msg = soapCall(dic, serviceId, applicationId); // Send SOAP Message to SOAP Server
String url = urlWs;
LOGGER.info("CALLING WS ....");
SOAPMessage soapResponse = soapConnection.call(msg, url);
// print SOAP Response
//soapResponse.writeTo(System.out);
ByteArrayOutputStream out = new ByteArrayOutputStream();
soapResponse.writeTo(out);
String strMsg = new String(out.toByteArray());
LOGGER.info("Response SOAP Message: {}",strMsg);
return strMsg;
}
} catch (SOAPException ex) {
throw ex;
} catch (UnsupportedOperationException ex) {
throw ex;
} catch (Exception ex) {
throw ex;
}
}
public class MySOAPConnection implements AutoCloseable {
public final SOAPConnection connection;
public MySOAPConnection(SOAPConnectionFactory soapConnectionFactory)
{
this.connection = soapConnectionFactory.createConnection();
}
@Override
public void close() throws Exception {
this.connection.close();
}
}
Note that when you use try-resource-close, the close() method should not be called explicitly, otherwise you would get double close()!
Upvotes: 1