java .lang.OutOfMemoryError: Java пространство кучи (тест JUnit) - PullRequest
0 голосов
/ 24 марта 2020

У меня есть класс, который я использую входной поток, а затем преобразовать его в строку. Также у меня есть тест Junit, где я получаю исключение «java .lang.OutOfMemoryError: Java куча пространства», я знаю, что проблема в том, что у меня утечка памяти в тесте, но я не понимаю как это исправить. Может кто-то знает, как это сделать?

Мой класс:

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));
    }

Stacktrace:

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$1.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$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)

1 Ответ

0 голосов
/ 24 марта 2020

Ваш вводный ввод - это бесконечно длинный поток байтов NUL (ноль). В какой-то момент есть попытка прочитать все это в память, что, конечно, заставляет вас исчерпать память, потому что она бесконечно длинна: ​​

    final InputStream inputStream = new InputStream()
    {
        @Override
        public int read()
        {
            return 0;
        }
    };

Быстрое решение состоит в том, чтобы ограничить его до известного размера, например 100 байт

final InputStream inputStream = new ByteArrayInputStream(new byte[100]);
...