(original) (raw)
Hi all,
we maybe found a bug in the com.sun.tools.javac.file.JavacFileManager; our tool makes heavy use of compiling classes during runtime, and after switching from JDK 8 to 11, we noticed hundreds of open files being created during list() and only closed when
JVM exists. The concerning lines of code are:
@Override @DefinedBy(Api.COMPILER)
public Iterable list(Location location,
String packageName,
Set kinds,
boolean recurse)
throws IOException
{
checkNotModuleOrientedLocation(location);
// validatePackageName(packageName);
nullCheck(packageName);
nullCheck(kinds);
Iterable path = getLocationAsPaths(location);
if (path == null)
return List.nil();
RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
ListBuffer results = new ListBuffer<>();
for (Path directory : path) {
Container container = getContainer(directory);
container.list(directory, subdirectory, kinds, recurse, results);
}
return results.toList();
}
We think, a container.close() is missing in the for loop. Without this, a filehandle is created for every container/directiry found here. To test this, the following code snipped can be used, but the location must be set property to find a valid path !=
null:
@Test
public void testFileManager( ) throws IOException
{
countOpenFiles( );
final Set kinds = new HashSet<>( );
kinds.add( javax.tools.JavaFileObject.Kind.OTHER );
kinds.add( javax.tools.JavaFileObject.Kind.SOURCE );
kinds.add( javax.tools.JavaFileObject.Kind.CLASS );
kinds.add( javax.tools.JavaFileObject.Kind.HTML );
final StandardJavaFileManager sfm =
ToolProvider.getSystemJavaCompiler( ).getStandardFileManager( null, null, null );
sfm.list( new JavaFileManager.Location( )
{
@Override
public boolean isOutputLocation( )
{
return false;
}
@Override
public String getName( )
{
return "CLASS\_NAME";
}
}, "com", kinds, true );
countOpenFiles( );
}
private void countOpenFiles( )
{
final String processName = java.lang.management.ManagementFactory.getRuntimeMXBean( ).getName( );
final long pid = Long.parseLong( processName.split( "@" )\[ 0 \] );
try
{
final Runtime rt = Runtime.getRuntime( );
final Process pr = rt.exec( "lsof -p " + pid );
int ctr = 0;
final BufferedReader br = new BufferedReader(
new InputStreamReader( pr.getInputStream( ) ) );
while ( ( br.readLine( ) ) != null )
ctr++;
pr.waitFor( );
pr.destroy( );
System.out.println( "Open files: " + ctr );
}
catch ( final Exception e )
{
e.printStackTrace( );
}
}
Can anybody confirm this?
Best,
Andreas