简体   繁体   English

java.lang.OutOfMemoryError:Java 堆空间(JUnit 测试)

[英]java.lang.OutOfMemoryError: Java heap space (JUnit test)

I have a class,which i use input stream and then conver it to string.我有一个类,我使用输入流,然后将其转换为字符串。 Also i have a Junit test,where i get the exception " java.lang.OutOfMemoryError: Java heap space",I know that the problem is that I have a memory leak in the test, but I don't understand how to fix it.Maybe someone know how to do it?另外我有一个 Junit 测试,在那里我得到异常“java.lang.OutOfMemoryError:Java 堆空间”,我知道问题是我在测试中有内存泄漏,但我不明白如何解决它.也许有人知道怎么做?

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

My JUnit test:我的 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)

Your mock input is an infinitely long stream of NUL (zero) bytes.您的模拟输入是无限长的 NUL(零)字节流。 At some point there's an attempt to read all of it into memory, which of course makes you run out of memory because it's infinitely long:在某些时候,尝试将所有内容读入内存,这当然会使您耗尽内存,因为它无限长:

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

A quick fix is to limit it to a known size like 100 bytes快速解决方法是将其限制为已知大小,例如 100 字节

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM