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 with Grails #209

Open
tsmortenson opened this issue Feb 1, 2018 · 1 comment
Open

Memory Leak with Grails #209

tsmortenson opened this issue Feb 1, 2018 · 1 comment

Comments

@tsmortenson
Copy link

tsmortenson commented Feb 1, 2018

I think I discovered a memory leak in the getTypeRegistryFor method of the org.springsource.loaded.TypeRegistry class.

I am admittedly a new user to Grails and my application has been having problems with running out of memory after a couple hours of operation.
Doing some memory profiling, I discovered that the "excludedLoaderInstances" ArrayList in the TypeRegistry class contains 4,102,267 elements. Most of which are different instances of a String "sun.misc.Launcher$ExtClassLoader@2b05039f" (All with the same hash at the end.)

Looking at the source in the getTypeRegistryFor method, I think I see the problem.

First is this code which is checking to see if the classLoader has already been excluded.
I still need to look into what this logging settings should be / are. But I am pretty sure that the problem is that my code is NOT getting into this check past the outer if.
This logic seems fairly critical, and nothing to do with logging? Is the outer check correct?


	if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) {
		if (excludedLoaderInstances.contains(classloader.toString())) {
			return null;
		}
	}

A few lines down in the method is the following code.
Here if the ClassLoader is marked as excluded, it is always added into the excludedLoaderInstances list without checking if it is already in there.


	for (String excluded : excludedLoaders) {
		if (classloaderName.startsWith(excluded)) {
			if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.FINEST)) {
				log.info("Classloader " + classloaderName + " has been deliberately excluded");
			}
			excludedLoaderInstances.add(classloader.toString());
			return null;
		}
	}

I am not yet sure why this is happening a few million times, but this looks to be the problem.

It seems like the performance of this could be greatly improved by replacing the ArrayList with a HashSet or something along those lines.

Any thoughts would be appreciated.
I will now look into why I am seeing this with Grails when most users are not...

@bp-FLN
Copy link

bp-FLN commented Nov 6, 2018

We're also affected by this. Using grails 3.1.15 here.
It happens when indexing tons of domain objects into elasticsearch.
After a while, the excludedLoaderInstances list has some million entries and the GC goes crazy.

Good news is that this only happens in local development mode.
When running in production environment, grails does not use the reloading agent.

I also took a look to the code and i'm pretty sure that @tsmortenson is right:
The "is the loader already excluded" check is broken.

I'm willing to submit a PR, but first i'd like to know whether this repo is still maintained.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants