WebSphere 8 内存泄漏
WebSphere 8 memory leaks
我有一个部署到 WebSphere 8.5 的应用程序(该应用程序是使用 java8/Spring 4 开发的)并且每天我都会收到很多转储文件,所以我决定使用 Eclipse Memory Analyzer 对其进行分析,结果是:
问题是我没有使用 axis 来调用 Web 服务,我只使用 Jersy 来调用 Rest Web 服务,并且
默认的 jdk class SoapConnection 用于 soap web 服务,下面是一些代码示例:
对于肥皂:
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;
}
}
休息:
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);
我想知道为什么会出现 Axis.Client 内存不足的情况,我该如何解决。如果有人能帮我解决,我将不胜感激。
关于您的第一个问题:为什么在您使用默认的 JDK class SOAPConnection 时使用 Apache Axis2?
class SOAPConnection 实际上只是 API 的一部分,可以有不同的实现。在您的情况下,WebSphere 提供了基于 Apache Axis2 的此 API 的实现,这就是为什么您看到那些 classes 的对象挥之不去的原因。
SOAPConnection Javadocs 状态:
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.
关于你问题的第二部分,我有一个假设。在 Javadocs 中我找不到是否必须调用 SOAPConnection.close(),但通常资源 classes 带有 close() 方法确实需要清理,否则会造成内存或其他资源泄漏。
您的代码确实调用了 close(),但是如果在关闭连接之前某处发生异常,执行将直接跳转到 catch(...) 并且连接不会被清理,从而造成内存泄漏。也许每次 SOAP 调用抛出异常时都会发生这种情况,这会泄漏您正在观察的内存。
您可以使用此处描述的 try-resource-close 模式解决此问题:https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
尝试在您的代码中进行以下更改。
编辑:
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();
}
}
注意当你使用try-resource-close时,不要显式调用close()方法,否则你会得到double close() !
使用 RestTemplate 而不是 SOAPConnection 修复了内存泄漏:
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;
我有一个部署到 WebSphere 8.5 的应用程序(该应用程序是使用 java8/Spring 4 开发的)并且每天我都会收到很多转储文件,所以我决定使用 Eclipse Memory Analyzer 对其进行分析,结果是:
问题是我没有使用 axis 来调用 Web 服务,我只使用 Jersy 来调用 Rest Web 服务,并且 默认的 jdk class SoapConnection 用于 soap web 服务,下面是一些代码示例: 对于肥皂:
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;
}
}
休息:
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);
我想知道为什么会出现 Axis.Client 内存不足的情况,我该如何解决。如果有人能帮我解决,我将不胜感激。
关于您的第一个问题:为什么在您使用默认的 JDK class SOAPConnection 时使用 Apache Axis2? class SOAPConnection 实际上只是 API 的一部分,可以有不同的实现。在您的情况下,WebSphere 提供了基于 Apache Axis2 的此 API 的实现,这就是为什么您看到那些 classes 的对象挥之不去的原因。 SOAPConnection Javadocs 状态:
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.
关于你问题的第二部分,我有一个假设。在 Javadocs 中我找不到是否必须调用 SOAPConnection.close(),但通常资源 classes 带有 close() 方法确实需要清理,否则会造成内存或其他资源泄漏。 您的代码确实调用了 close(),但是如果在关闭连接之前某处发生异常,执行将直接跳转到 catch(...) 并且连接不会被清理,从而造成内存泄漏。也许每次 SOAP 调用抛出异常时都会发生这种情况,这会泄漏您正在观察的内存。
您可以使用此处描述的 try-resource-close 模式解决此问题:https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html 尝试在您的代码中进行以下更改。
编辑:
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();
}
}
注意当你使用try-resource-close时,不要显式调用close()方法,否则你会得到double close() !
使用 RestTemplate 而不是 SOAPConnection 修复了内存泄漏:
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;