my english is poor, but I'm very eager to solve the problem.
Play Version
2.3.4
Scala
2.1.1
Operating System
CentOS release 6.9 (Final)
Linux version 2.6.32-696.10.2.el6.x86_64 (
mock...@c1bl.rdu2.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC) ) #1 SMP Tue Sep 12 14:33:29 UTC 2017
JDK
java version "1.7.0_67"
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
Behavior
Some time ago,found res memory is constantly increasing, which is much larger than xmx. I learned that when serving application’s static resources,playframework call Resources.isUrlConnectionADirectory,make sure it's not a directory. I use greys-anatomy(like btrace) get the call stack of Inflater constructor,found JarFile getInputStream new a Inflater object, and when close, return it to inflaterCache. Why not get from the cache, but a new one(in other words, Sometimes borrowed is not returned). ps: when jmap heap:live trigger full gc, res memory droped.
in order to test and verify if getInputStream of application'assets.jar[val is = jar.getJarFile.getInputStream(jar.getJarEntry)] resulting in inflater memory leak, I unzip assets.jar and place directory in classpath, restart application, found the res memory no longer increase much larger.
/**
* Tries to work out whether the given URL connection is a directory or not.
*
* Depends on the URL connection type whether it's accurate. If it's unable to determine whether it's a directory,
* this returns false.
*/
def isUrlConnectionADirectory(urlConnection: URLConnection) = urlConnection match {
case file: FileURLConnection => new File(file.getURL.toURI).isDirectory //unzip asset.jar, execute here, memory perform normally
case jar: JarURLConnection =>
if (jar.getJarEntry.isDirectory) {
true
} else {
// JarEntry.isDirectory is rubbish....
val is = jar.getJarFile.getInputStream(jar.getJarEntry)
if (is == null) {
true
} else {
is.close()
false
}
}
case other => false
}