java.lang.OutOfMemoryError: Java heap space (JUnit test)
java.lang.OutOfMemoryError: Java heap space (JUnit test)
我有一个 class,我使用输入流然后将其转换为字符串。
我还有一个 Junit 测试,在那里我得到异常“java.lang.OutOfMemoryError:Java heap space”,我知道问题是我在测试中有内存泄漏,但我不明白如何解决 it.Maybe 有人知道怎么做吗?
我的class:
public class IntegrationMonitoringHttpInterceptor implements ClientHttpRequestInterceptor
{
private static final Logger LOG = LoggerFactory.getLogger(IntegrationMonitoringHttpInterceptor.class);
@Resource
private IntegrationMessageService integrationMessageService;
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] bytes, final ClientHttpRequestExecution clientHttpRequestExecution) throws IOException
{
final String requestMethod = request.getMethod().toString();
final String requestURI = request.getURI().toString();
final String requestHeaders = request.getHeaders().toString();
final String requestBody = new String(bytes, StandardCharsets.UTF_8);
final String requestMessageBody = requestMethod + "\n" + requestURI + "\n" + requestHeaders + "\n" + requestBody;
final IntegrationMessageBatchModel batch = saveRequest(requestURI, requestMessageBody);
try
{
final ClientHttpResponse response = clientHttpRequestExecution.execute(request, bytes);
final String responseStatusCode = response.getStatusCode().toString();
final String responseStatusText = response.getStatusText();
final String responseHeaders = response.getHeaders().toString();
final InputStream responseInputStream = response.getBody();
final String responseBody = IOUtils.toString(responseInputStream, StandardCharsets.UTF_8.name()); //in the test, a memory leak occurs here
IOUtils.closeQuietly(responseInputStream);
responseInputStream.close();
final String responseMessageBody = responseStatusCode + "\n" + responseStatusText + responseHeaders + "\n" + responseBody;
saveResponse(responseMessageBody, batch, requestURI);
return response;
}
catch (Exception exception)
{
integrationMessageService.createMessageInBatch(exception.getMessage(), batch);
LOG.warn("Cannot execute request due to unexpected error", exception);
throw exception;
}
}
private IntegrationMessageBatchModel saveRequest(final String requestURI, final String requestMessageBody)
{
try
{
IntegrationMessageBatchModel integrationMessageBatchModel = integrationMessageService.createBatch(IntegrationExchangeType.HTTP, requestURI);
integrationMessageService.createMessageInBatch(requestMessageBody, integrationMessageBatchModel);
return integrationMessageBatchModel;
}
catch (Exception exception)
{
LOG.warn("Cannot save message due to unexpected error", exception);
return null;
}
}
private void saveResponse(final String response, final IntegrationMessageBatchModel batchModel, final String requestURI)
{
try
{
if (batchModel != null)
{
integrationMessageService.createMessageInBatch(response, batchModel);
}
else
{
IntegrationMessageBatchModel integrationMessageBatchModel = integrationMessageService.createBatch(IntegrationExchangeType.HTTP, requestURI);
integrationMessageService.createMessageInBatch(response, integrationMessageBatchModel);
}
}
catch (Exception exception)
{
LOG.warn("Cannot save message due to unexpected error", exception);
}
}
}
我的 JUnit 测试:
@RunWith(MockitoJUnitRunner.class)
@UnitTest
public class IntegrationMonitoringHttpInterceptorTest
{
@Rule
public ExpectedException thrown = ExpectedException.none();
@Mock
private IntegrationMessageService integrationMessageService;
@Mock
private HttpRequest httpRequest;
@Mock
private ClientHttpRequestExecution clientHttpRequestExecution;
@Mock
private ClientHttpResponse clientHttpResponse;
@InjectMocks
private IntegrationMonitoringHttpInterceptor integrationMonitoringHttpInterceptor = new IntegrationMonitoringHttpInterceptor();
@Test
public void intercept() throws Exception
{
final String body = "http message";
final URI uri = new URI("http://headers.jsontest.com/");
final InputStream inputStream = new InputStream()
{
@Override
public int read()
{
return 0;
}
};
when(httpRequest.getURI()).thenReturn(uri);
when(httpRequest.getMethod()).thenReturn(HttpMethod.POST);
when(httpRequest.getHeaders()).thenReturn(new HttpHeaders());
when(clientHttpRequestExecution.execute(httpRequest, body.getBytes(StandardCharsets.UTF_8))).thenReturn(clientHttpResponse);
when(clientHttpResponse.getStatusCode()).thenReturn(HttpStatus.OK);
when(clientHttpResponse.getStatusText()).thenReturn("OK");
when(clientHttpResponse.getHeaders()).thenReturn(new HttpHeaders());
when(clientHttpResponse.getBody()).thenReturn(inputStream);
when(integrationMessageService.createBatch(eq(IntegrationExchangeType.HTTP), eq(uri.toString())))
.thenReturn(new IntegrationMessageBatchModel());
when(integrationMessageService.createMessageInBatch(eq(body), any(IntegrationMessageBatchModel.class)))
.thenReturn(new IntegrationMessageModel());
when(integrationMessageService.createMessageInBatch(contains(body), any(IntegrationMessageBatchModel.class)))
.thenReturn(new IntegrationMessageModel());
integrationMonitoringHttpInterceptor.intercept(httpRequest, body.getBytes(StandardCharsets.UTF_8), clientHttpRequestExecution);
verify(clientHttpRequestExecution, times(1)).execute(httpRequest, body.getBytes(StandardCharsets.UTF_8));
verify(integrationMessageService, times(1)).createBatch(eq(IntegrationExchangeType.HTTP), eq(uri.toString()));
verify(integrationMessageService, times(2)).createMessageInBatch(anyString(), any(IntegrationMessageBatchModel.class));
}
堆栈跟踪:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2367)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:535)
at java.lang.StringBuilder.append(StringBuilder.java:204)
at org.apache.commons.io.output.StringBuilderWriter.write(StringBuilderWriter.java:138)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2002)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1980)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1957)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1907)
at org.apache.commons.io.IOUtils.toString(IOUtils.java:778)
at org.apache.commons.io.IOUtils.toString(IOUtils.java:803)
at core.interceptors.IntegrationMonitoringHttpInterceptor.intercept(IntegrationMonitoringHttpInterceptor.java:48)
at core.interceptors.IntegrationMonitoringHttpInterceptorTest.intercept(IntegrationMonitoringHttpInterceptorTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
at org.junit.rules.RunRules.evaluate(RunRules.java:18)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
at org.junit.runners.ParentRunner.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:50)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:222)
您的模拟输入是无限长的 NUL(零)字节流。在某些时候,会尝试将所有内容读入内存,这当然会让你 运行 内存不足,因为它是无限长的:
final InputStream inputStream = new InputStream()
{
@Override
public int read()
{
return 0;
}
};
快速解决方法是将其限制为已知大小,例如 100 字节
final InputStream inputStream = new ByteArrayInputStream(new byte[100]);
我有一个 class,我使用输入流然后将其转换为字符串。 我还有一个 Junit 测试,在那里我得到异常“java.lang.OutOfMemoryError:Java heap space”,我知道问题是我在测试中有内存泄漏,但我不明白如何解决 it.Maybe 有人知道怎么做吗?
我的class:
public class IntegrationMonitoringHttpInterceptor implements ClientHttpRequestInterceptor
{
private static final Logger LOG = LoggerFactory.getLogger(IntegrationMonitoringHttpInterceptor.class);
@Resource
private IntegrationMessageService integrationMessageService;
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] bytes, final ClientHttpRequestExecution clientHttpRequestExecution) throws IOException
{
final String requestMethod = request.getMethod().toString();
final String requestURI = request.getURI().toString();
final String requestHeaders = request.getHeaders().toString();
final String requestBody = new String(bytes, StandardCharsets.UTF_8);
final String requestMessageBody = requestMethod + "\n" + requestURI + "\n" + requestHeaders + "\n" + requestBody;
final IntegrationMessageBatchModel batch = saveRequest(requestURI, requestMessageBody);
try
{
final ClientHttpResponse response = clientHttpRequestExecution.execute(request, bytes);
final String responseStatusCode = response.getStatusCode().toString();
final String responseStatusText = response.getStatusText();
final String responseHeaders = response.getHeaders().toString();
final InputStream responseInputStream = response.getBody();
final String responseBody = IOUtils.toString(responseInputStream, StandardCharsets.UTF_8.name()); //in the test, a memory leak occurs here
IOUtils.closeQuietly(responseInputStream);
responseInputStream.close();
final String responseMessageBody = responseStatusCode + "\n" + responseStatusText + responseHeaders + "\n" + responseBody;
saveResponse(responseMessageBody, batch, requestURI);
return response;
}
catch (Exception exception)
{
integrationMessageService.createMessageInBatch(exception.getMessage(), batch);
LOG.warn("Cannot execute request due to unexpected error", exception);
throw exception;
}
}
private IntegrationMessageBatchModel saveRequest(final String requestURI, final String requestMessageBody)
{
try
{
IntegrationMessageBatchModel integrationMessageBatchModel = integrationMessageService.createBatch(IntegrationExchangeType.HTTP, requestURI);
integrationMessageService.createMessageInBatch(requestMessageBody, integrationMessageBatchModel);
return integrationMessageBatchModel;
}
catch (Exception exception)
{
LOG.warn("Cannot save message due to unexpected error", exception);
return null;
}
}
private void saveResponse(final String response, final IntegrationMessageBatchModel batchModel, final String requestURI)
{
try
{
if (batchModel != null)
{
integrationMessageService.createMessageInBatch(response, batchModel);
}
else
{
IntegrationMessageBatchModel integrationMessageBatchModel = integrationMessageService.createBatch(IntegrationExchangeType.HTTP, requestURI);
integrationMessageService.createMessageInBatch(response, integrationMessageBatchModel);
}
}
catch (Exception exception)
{
LOG.warn("Cannot save message due to unexpected error", exception);
}
}
}
我的 JUnit 测试:
@RunWith(MockitoJUnitRunner.class)
@UnitTest
public class IntegrationMonitoringHttpInterceptorTest
{
@Rule
public ExpectedException thrown = ExpectedException.none();
@Mock
private IntegrationMessageService integrationMessageService;
@Mock
private HttpRequest httpRequest;
@Mock
private ClientHttpRequestExecution clientHttpRequestExecution;
@Mock
private ClientHttpResponse clientHttpResponse;
@InjectMocks
private IntegrationMonitoringHttpInterceptor integrationMonitoringHttpInterceptor = new IntegrationMonitoringHttpInterceptor();
@Test
public void intercept() throws Exception
{
final String body = "http message";
final URI uri = new URI("http://headers.jsontest.com/");
final InputStream inputStream = new InputStream()
{
@Override
public int read()
{
return 0;
}
};
when(httpRequest.getURI()).thenReturn(uri);
when(httpRequest.getMethod()).thenReturn(HttpMethod.POST);
when(httpRequest.getHeaders()).thenReturn(new HttpHeaders());
when(clientHttpRequestExecution.execute(httpRequest, body.getBytes(StandardCharsets.UTF_8))).thenReturn(clientHttpResponse);
when(clientHttpResponse.getStatusCode()).thenReturn(HttpStatus.OK);
when(clientHttpResponse.getStatusText()).thenReturn("OK");
when(clientHttpResponse.getHeaders()).thenReturn(new HttpHeaders());
when(clientHttpResponse.getBody()).thenReturn(inputStream);
when(integrationMessageService.createBatch(eq(IntegrationExchangeType.HTTP), eq(uri.toString())))
.thenReturn(new IntegrationMessageBatchModel());
when(integrationMessageService.createMessageInBatch(eq(body), any(IntegrationMessageBatchModel.class)))
.thenReturn(new IntegrationMessageModel());
when(integrationMessageService.createMessageInBatch(contains(body), any(IntegrationMessageBatchModel.class)))
.thenReturn(new IntegrationMessageModel());
integrationMonitoringHttpInterceptor.intercept(httpRequest, body.getBytes(StandardCharsets.UTF_8), clientHttpRequestExecution);
verify(clientHttpRequestExecution, times(1)).execute(httpRequest, body.getBytes(StandardCharsets.UTF_8));
verify(integrationMessageService, times(1)).createBatch(eq(IntegrationExchangeType.HTTP), eq(uri.toString()));
verify(integrationMessageService, times(2)).createMessageInBatch(anyString(), any(IntegrationMessageBatchModel.class));
}
堆栈跟踪:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2367)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:535)
at java.lang.StringBuilder.append(StringBuilder.java:204)
at org.apache.commons.io.output.StringBuilderWriter.write(StringBuilderWriter.java:138)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2002)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1980)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1957)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1907)
at org.apache.commons.io.IOUtils.toString(IOUtils.java:778)
at org.apache.commons.io.IOUtils.toString(IOUtils.java:803)
at core.interceptors.IntegrationMonitoringHttpInterceptor.intercept(IntegrationMonitoringHttpInterceptor.java:48)
at core.interceptors.IntegrationMonitoringHttpInterceptorTest.intercept(IntegrationMonitoringHttpInterceptorTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
at org.junit.rules.RunRules.evaluate(RunRules.java:18)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
at org.junit.runners.ParentRunner.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access[=12=]0(ParentRunner.java:50)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:222)
您的模拟输入是无限长的 NUL(零)字节流。在某些时候,会尝试将所有内容读入内存,这当然会让你 运行 内存不足,因为它是无限长的:
final InputStream inputStream = new InputStream()
{
@Override
public int read()
{
return 0;
}
};
快速解决方法是将其限制为已知大小,例如 100 字节
final InputStream inputStream = new ByteArrayInputStream(new byte[100]);