Java HTTP 请求中的内存泄漏
Java Memory Leak in HTTP requests
我有一个持续运行的 Java 应用程序。此应用程序向云服务器发出 HTTP 请求。问题是每次请求时,内存消耗都会增加,直到达到机器完全冻结的程度。我隔离了部分代码,我确定问题出在发出此 http 请求的代码块上。通过 prometheus / Grafana 分析 JVM 数字,我看到非堆内存(codecache 和元空间)的使用在不断增加,如图所示 here
在上图中,每当线路出现下降时,就是内存消耗达到 98% 时,Monit 会杀死应用程序。
导致这种内存消耗的方法如下(它执行了大约 300 次,直到它在初始化中耗尽了 1.5GB 多一点的可用内存)。
public AbstractRestReponse send(RestRequest request){
BufferedReader in = null;
OutputStream fout = null;
URLConnection conn = null;
InputStreamReader inputStreamReader = null;
String result = "";
try {
MultipartEntityBuilder mb = MultipartEntityBuilder.create();// org.apache.http.entity.mime
for (String key : request.getParams().keySet()) {
String value = (String) request.getParams().get(key);
// System.out.println(key + " = " + value);
mb.addTextBody(key, value);
}
if (request.getFile() != null) {
mb.addBinaryBody("file", request.getFile());
}
org.apache.http.HttpEntity e = mb.build();
conn = new URL(request.getUrl()).openConnection();
conn.setDoOutput(true);
conn.addRequestProperty(e.getContentType().getName(), e.getContentType().getValue());// header "Content-Type"...
conn.addRequestProperty("Content-Length", String.valueOf(e.getContentLength()));
fout = conn.getOutputStream();
e.writeTo(fout);// write multi part data...
inputStreamReader = new InputStreamReader(conn.getInputStream());
in = new BufferedReader(inputStreamReader);
String line;
while ((line = in.readLine()) != null) {
result += line;
}
String text = result.toString();
return objectMapper.readValue(text, FacialApiResult.class);
}catch (Exception e) {
e.printStackTrace();
return null;
}finally {
try {
inputStreamReader.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
conn.getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fout.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
您似乎已经处理了 finally 块中所有可能的结束部分。无论如何,如果您的应用程序是 Java 7+ 上的 运行,最好使用 try-with 资源来安全地关闭所有 Closeable 对象。如果问题没有解决,这可能会进一步隔离问题。
想到((HttpURLConnection)conn).disconnect()
。字符串连接也是耗尽时间 and 的内存。删除换行符时有一个小错误。
NullPointerExceptions 可能会在 finally
块中出现,当由于异常而未达到打开时。但你应该检查一下。
public AbstractRestReponse send(RestRequest request) {
URLConnection conn = null;
try {
MultipartEntityBuilder mb = MultipartEntityBuilder.create();// org.apache.http.entity.mime
for (String key : request.getParams().keySet()) {
String value = (String) request.getParams().get(key);
mb.addTextBody(key, value);
}
if (request.getFile() != null) {
mb.addBinaryBody("file", request.getFile());
}
org.apache.http.HttpEntity e = mb.build();
conn = new URL(request.getUrl()).openConnection();
conn.setDoOutput(true);
conn.addRequestProperty(e.getContentType().getName(), e.getContentType().getValue());// header "Content-Type"...
conn.addRequestProperty("Content-Length", String.valueOf(e.getContentLength()));
try (fout = conn.getOutputStream()){
e.writeTo(fout);// write multi part data...
}
StringBuilder resullt = new StringBuilder(2048);
try (BufferedReader in = new InputStreamReader(conn.getInputStream(),
StandardCharsets.UTF_8)) { // Charset
String line;
while ((line = in.readLine()) != null) {
result.append(line).append('\n'); // Newline
}
}
String text = result.toString();
return objectMapper.readValue(text, FacialApiResult.class);
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (conn != null) {
try {
if (conn instanceof HttpURLConnection) {
((HttpURLConnection) conn).disconnect();
}
} catch (IOException e) {
e.printStackTrace(); //Better logger
}
}
}
return null;
}
- 我明确定义了字符集(UTF-8 可能是错误的)- 目前它是服务器的默认值。
- 使用了 StringBuilder,并添加了缺失的换行符,这可能会导致错误的解析。
- Try-with-resources 自动关闭,早一点。希望这不会破坏任何东西。
- 当它是一个 HttpURLConnection 时断开连接。注意 instanceof 可能在单元测试模拟中发挥作用。
我有一个持续运行的 Java 应用程序。此应用程序向云服务器发出 HTTP 请求。问题是每次请求时,内存消耗都会增加,直到达到机器完全冻结的程度。我隔离了部分代码,我确定问题出在发出此 http 请求的代码块上。通过 prometheus / Grafana 分析 JVM 数字,我看到非堆内存(codecache 和元空间)的使用在不断增加,如图所示 here
在上图中,每当线路出现下降时,就是内存消耗达到 98% 时,Monit 会杀死应用程序。
导致这种内存消耗的方法如下(它执行了大约 300 次,直到它在初始化中耗尽了 1.5GB 多一点的可用内存)。
public AbstractRestReponse send(RestRequest request){
BufferedReader in = null;
OutputStream fout = null;
URLConnection conn = null;
InputStreamReader inputStreamReader = null;
String result = "";
try {
MultipartEntityBuilder mb = MultipartEntityBuilder.create();// org.apache.http.entity.mime
for (String key : request.getParams().keySet()) {
String value = (String) request.getParams().get(key);
// System.out.println(key + " = " + value);
mb.addTextBody(key, value);
}
if (request.getFile() != null) {
mb.addBinaryBody("file", request.getFile());
}
org.apache.http.HttpEntity e = mb.build();
conn = new URL(request.getUrl()).openConnection();
conn.setDoOutput(true);
conn.addRequestProperty(e.getContentType().getName(), e.getContentType().getValue());// header "Content-Type"...
conn.addRequestProperty("Content-Length", String.valueOf(e.getContentLength()));
fout = conn.getOutputStream();
e.writeTo(fout);// write multi part data...
inputStreamReader = new InputStreamReader(conn.getInputStream());
in = new BufferedReader(inputStreamReader);
String line;
while ((line = in.readLine()) != null) {
result += line;
}
String text = result.toString();
return objectMapper.readValue(text, FacialApiResult.class);
}catch (Exception e) {
e.printStackTrace();
return null;
}finally {
try {
inputStreamReader.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
conn.getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fout.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
您似乎已经处理了 finally 块中所有可能的结束部分。无论如何,如果您的应用程序是 Java 7+ 上的 运行,最好使用 try-with 资源来安全地关闭所有 Closeable 对象。如果问题没有解决,这可能会进一步隔离问题。
((HttpURLConnection)conn).disconnect()
。字符串连接也是耗尽时间 and 的内存。删除换行符时有一个小错误。
NullPointerExceptions 可能会在 finally
块中出现,当由于异常而未达到打开时。但你应该检查一下。
public AbstractRestReponse send(RestRequest request) {
URLConnection conn = null;
try {
MultipartEntityBuilder mb = MultipartEntityBuilder.create();// org.apache.http.entity.mime
for (String key : request.getParams().keySet()) {
String value = (String) request.getParams().get(key);
mb.addTextBody(key, value);
}
if (request.getFile() != null) {
mb.addBinaryBody("file", request.getFile());
}
org.apache.http.HttpEntity e = mb.build();
conn = new URL(request.getUrl()).openConnection();
conn.setDoOutput(true);
conn.addRequestProperty(e.getContentType().getName(), e.getContentType().getValue());// header "Content-Type"...
conn.addRequestProperty("Content-Length", String.valueOf(e.getContentLength()));
try (fout = conn.getOutputStream()){
e.writeTo(fout);// write multi part data...
}
StringBuilder resullt = new StringBuilder(2048);
try (BufferedReader in = new InputStreamReader(conn.getInputStream(),
StandardCharsets.UTF_8)) { // Charset
String line;
while ((line = in.readLine()) != null) {
result.append(line).append('\n'); // Newline
}
}
String text = result.toString();
return objectMapper.readValue(text, FacialApiResult.class);
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (conn != null) {
try {
if (conn instanceof HttpURLConnection) {
((HttpURLConnection) conn).disconnect();
}
} catch (IOException e) {
e.printStackTrace(); //Better logger
}
}
}
return null;
}
- 我明确定义了字符集(UTF-8 可能是错误的)- 目前它是服务器的默认值。
- 使用了 StringBuilder,并添加了缺失的换行符,这可能会导致错误的解析。
- Try-with-resources 自动关闭,早一点。希望这不会破坏任何东西。
- 当它是一个 HttpURLConnection 时断开连接。注意 instanceof 可能在单元测试模拟中发挥作用。