Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak when using @Async after upgrading from 5.1 to 5.2 #23571

Closed
arian opened this issue Sep 3, 2019 · 15 comments
Closed

Memory leak when using @Async after upgrading from 5.1 to 5.2 #23571

arian opened this issue Sep 3, 2019 · 15 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: feedback-provided Feedback has been provided type: regression A bug that is also a regression
Milestone

Comments

@arian
Copy link

arian commented Sep 3, 2019

Affects: 5.2.0.RC1


In our application I upgraded from spring-framework 5.1.9 to 5.2.0.RC1 and our tests started leaking memory.

Previously it looked like this in VisualVM:

image

And now it looks like this:

image

I've made a heapdump to see where the memory is going:

image

I've seen something similar in our application previously, but that was solved by using @MockBean instead of a lot of @ContextConfiguration with @Configuration classes inside our test classes to override beans with mocked objects 🤔...

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Sep 3, 2019
@sbrannen
Copy link
Member

sbrannen commented Sep 6, 2019

Hi @arian,

Can you possibly reduce this to the smallest application possible that demonstrates the behavior (and provide access to the full example application)?

At the very least, it would be helpful to know what kind of components are active in the ApplicationContext and what configuration (i.e., annotations) you are using in your tests.

Without being able to debug it, we don't really have much to go on.

Thanks in advance!

@sbrannen sbrannen added the status: waiting-for-feedback We need additional information before we can continue label Sep 6, 2019
@arian
Copy link
Author

arian commented Sep 7, 2019

Yes I completely understand! It's difficult to create a reproducible small application for me as I don't really figured out what causes the problem.

At the very least, it would be helpful to know what kind of components are active in the ApplicationContext and what configuration (i.e., annotations) you are using in your tests.

Is there an easy way to print a log of this or something?

Anyway I'll try to do some more testing after the weekend and see if I can report back!

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 7, 2019
@sbrannen
Copy link
Member

sbrannen commented Sep 10, 2019

Is there an easy way to print a log of this or something?

Not for the annotations is use; however, it appears that you're using @Async. So perhaps focusing on that part of your application might reveal something.

If you're using Spring Boot, you could use the actuator endpoint to get a list of all beans in the ApplicationContext. Otherwise, you might try Spring's LiveBeansView support.

Anyway I'll try to do some more testing after the weekend and see if I can report back!

Thanks.

@arian
Copy link
Author

arian commented Sep 11, 2019

The problem seems to occur with @EnableAsync. Without it running some tests look like:

image

With @EnableAsync

image

Also a heapdump when running without @EnableAsync doesn't show the list with org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor objects in memory.

Also commenting out all @Async seem to run the tests ok too.

Checked with 5.2.0.RC2, same result as RC1.

@sbrannen
Copy link
Member

Thanks for investigating further and providing us the detailed feedback!

We'll look into it.

@sbrannen sbrannen added this to the 5.2 GA milestone Sep 11, 2019
@sbrannen
Copy link
Member

Tentatively slated for 5.2 GA for further investigation since this appears to be a regression.

@sbrannen
Copy link
Member

Hi @arian,

Since this appears to be a regression, we'd really like to get to the bottom of this before we release Spring Framework 5.2 GA next week.

We brainstormed a bit within the team about possible causes for this, but we're really just shooting in the dark without being able to debug a project that reproduces the memory leak.

Based on your knowledge that the issue involves the use of @Async, we would be very grateful if you could provide us a small application that reproduces the problem.

If that's not possible, can you please run your test suite against 5.2 M1, 5.2 M2, and 5.2 M3 and let us know for which milestone versions you experience the problem?

That would help us at least to pinpoint when the regression was introduced.

Thanks in advance!

@sbrannen
Copy link
Member

sbrannen commented Sep 17, 2019

@arian, don't worry about the requests in my previous comment.

The following test class seems to reproduce the problem, if you limit the max heap size to 64 MB.

The test class succeeds unless you uncomment @DirtiesContext, in which case it leads to java.lang.OutOfMemoryError: GC overhead limit exceeded.

@SpringJUnitConfig
class AsyncTestCase {

	@RepeatedTest(1000)
	// @DirtiesContext
	void test() {
	}

	@Configuration
	@EnableAsync
	@Import(AsyncService.class)
	static class Config {
	}

	static class AsyncService {

		@Async
		void doSomething() {
		}
	}
}

@sbrannen
Copy link
Member

@arian, one last question:

Which testing framework are you using?

  • JUnit 4
  • JUnit Jupiter
  • TestNG
  • ?

@arian
Copy link
Author

arian commented Sep 17, 2019

Cool, I was just looking into a way to reproduce it!

We're still using junit 4 at the moment.

@sbrannen
Copy link
Member

Cool, I was just looking into a way to reproduce it!

We're still using junit 4 at the moment.

OK. Thanks for the feedback.

@sbrannen
Copy link
Member

Same error occurs with JUnit 4:

@RunWith(SpringRunner.class)
public class AsyncTestCase {

	@Test
	@Repeat(1000)
	@DirtiesContext
	public void test() {
	}

	@Configuration
	@EnableAsync
	@Import(AsyncService.class)
	static class Config {
	}

	static class AsyncService {

		@Async
		void doSomething() {
		}
	}
}

@sbrannen
Copy link
Member

@arian, can you confirm that executing your test suite with -Dcglib.useCache=false works without a memory leak?

@sbrannen
Copy link
Member

Mystery solved: the newly introduced AnnotationMatchingPointcut.AnnotationCandidateClassFilter class doesn't implement equals().

I've got a fix locally that I'll apply tomorrow to master.

@sbrannen sbrannen added type: regression A bug that is also a regression and removed status: waiting-for-triage An issue we've not yet triaged or decided on for: team-attention labels Sep 17, 2019
@sbrannen sbrannen self-assigned this Sep 17, 2019
@sbrannen sbrannen changed the title Memory leak (in tests) after upgrading from 5.1 to 5.2 Memory leak when using @Async after upgrading from 5.1 to 5.2 Sep 17, 2019
@arian
Copy link
Author

arian commented Sep 18, 2019

@arian, can you confirm that executing your test suite with -Dcglib.useCache=false works without a memory leak?

With that it seems to work without leaks.

Mystery solved

Great!

@sbrannen sbrannen added the in: core Issues in core modules (aop, beans, core, context, expression) label Sep 18, 2019
sbrannen added a commit to sbrannen/spring-framework that referenced this issue Sep 19, 2019
While resolving the regression raised in spring-projectsgh-23571, it came to our
attention that not all of our ClassFilter and MethodMatcher
implementations were properly cacheable with CGLIB generated proxies
due to missing (or improper) equals() and hashCode() implementations.

Although such deficiencies may not manifest themselves as bugs in Core
Spring's default arrangements, these might cause issues in custom
arrangements in user applications.

This commit addresses this by ensuring that ClassFilter and
MethodMatcher implementations properly implement equals() and
hashCode(). In addition, missing toString() implementations have been
added to improve diagnostics for logging and debugging.

Closes spring-projectsgh-23659
sbrannen added a commit that referenced this issue Sep 19, 2019
While resolving the regression raised in gh-23571, it came to our
attention that not all of our ClassFilter and MethodMatcher
implementations were properly cacheable with CGLIB generated proxies
due to missing (or improper) equals() and hashCode() implementations.

Although such deficiencies may not manifest themselves as bugs in Core
Spring's default arrangements, these might cause issues in custom
arrangements in user applications.

This commit addresses this by ensuring that ClassFilter and
MethodMatcher implementations properly implement equals() and
hashCode(). In addition, missing toString() implementations have been
added to improve diagnostics for logging and debugging.

Closes gh-23659
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: feedback-provided Feedback has been provided type: regression A bug that is also a regression
Projects
None yet
Development

No branches or pull requests

3 participants