Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4715154
Votes 0
Synopsis (fs) Cannot delete file if memory mapped with FileChannel.map (windows)
Category java:classes_nio
Reported Against 1.4 , 1.4.1_01
Release Fixed
State 11-Closed, Will Not Fix, bug
Priority: 3-Medium
Related Bugs 4469299 , 4829325 , 4831749
Submit Date 16-JUL-2002
Description




FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION : Microsoft Windows 2000
[Version 5.00.2195]


A DESCRIPTION OF THE PROBLEM :
A file opened for read-only access and memory mapped using
the map method of FileChannel cannot be deleted even when
the channel is closed.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Compile and run the source code
2. Run it as follows: java testFileDelete filename
   where filename is the name of the file to be deleted.


EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected: List the contents of the file specified on the
command line and delete it.
Actual: Lists the contents of the file, however fails to
delete it.


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Could not delete file testdel.txt

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class testFileDelete {

public static void main(String[] args) {


FileInputStream fis = null;

if (args.length < 1) {
System.err.println("Usage: java testFileDelete <filename>");
System.exit(1);
}

File f = new File(args[0]);


try {
// Open the file
fis = new FileInputStream(f);
} catch (FileNotFoundException ex) {
System.err.println("Error! " + ex.getMessage());
System.exit(2);
}


try {
// Get a channel from the stream
FileChannel fc = fis.getChannel();

// Map the file into memory
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int)fc.size());

// Do something interesting here. For this example, just print the
// contents of the file.

// Decode the file into a char buffer, so we can print the contents.
Charset cs = Charset.forName("8859_1");
CharsetDecoder cd = cs.newDecoder();
CharBuffer cb = cd.decode(bb);

// Now print it out to standard output
System.out.print(cb);

// Close the channel and the stream
fc.close();

// Close the input stream even though closing the
// channel should do this
fis.close();
} catch (IOException ex) {
System.err.println("Error! " + ex.getMessage());
System.exit(3);
}

// Done processing file. Now delete it.
boolean deleted = f.delete();
if (!(deleted)) {
System.err.println("Could not delete file " + f.getName());
System.exit(2);
}
}

}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
FileChannel.map seems to be causing this problem. A
possible workaround is to not use the NIO package.
(Review ID: 153724) 
======================================================================




FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build
1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
If a file has been memory mapped (using
java.nio.channels.FileChannel.map), File.deleteOnExit does
not work reliably. It depends on whether the mapped buffer
has been 'finalized' before the JVM exits.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the attached code. You have a 1KB 'temporary' file
left behind.
2. If you uncomment the System.gc() line, the subsequent
delete may work (but in my actual code this is unreliable).


EXPECTED VERSUS ACTUAL BEHAVIOR :
I would expect the File.deleteOnExit to always delete the
file. This would require the JVM to unmap any mapped files
before deleteing 'temporary' files. This failure I consider
a bug.

There is a second issue, which is the difficulty of using
File.delete and  xxxxx  methods when we can't control the
timing of unmapping. I will submit a separate RFE for this.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

class TestMemoryMapping
{
	public static void main(String[] args)
	{
		try
		{
			File f = File.createTempFile("Test", null);
			f.deleteOnExit();
			RandomAccessFile raf = new RandomAccessFile(f, "rw");
			raf.setLength(1024);
			FileChannel channel = raf.getChannel();
			MappedByteBuffer buffer = channel.map
(FileChannel.MapMode.READ_WRITE, 0, 1024);
			channel.close();
			raf.close();
			buffer = null;
			// System.gc();
			if (f.delete())
				System.out.println("Temporary file
deleted: "+f);
			else
				System.out.println("Not yet deleted: "+f);
		}
		catch (IOException ex)
		{
			ex.printStackTrace();
		}
	}
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Calling System.gc sometimes works.
(Review ID: 153921)
======================================================================
Work Around
N/A
Evaluation
We cannot fix this.  Windows does not allow a mapped file to be deleted.  This
problem should be ameliorated somewhat once we fix our garbage collectors to
deallocate direct buffers more promptly (see 4469299), but otherwise there's
nothing we can do about this.

--  xxxxx@xxxxx  2002/7/16
Comments
  
  Include a link with my name & email   

Submitted On 18-AUG-2002
mthornton
Of course you CAN fix it. You would need to process 
deleteOnExit actions after all java code has stopped (and 
thus no longer using mapped buffers), and just release any 
remaining mappings at this point.


Submitted On 04-DEC-2003
KornySietsma
It would be a start, to give us a method to un-map a 
mappedbytebuffer manually.  There appears to be no way to 
do this without waiting for it to be garbage collected, which 
makes this feature all but unusable.
Note that bug 4469299 seems to be unavailable in the bug 
parade.


Submitted On 25-MAR-2004
schleinm
The evaluation is INCORRECT:  please see the section of this
MSDN article entitled "Unmapping a View of a Memory-Mapped File"
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dngenlib/html/msdn_manamemo.asp)

... the delete() method ought to unmap this automatically,
then delete!

ALSO...

The best "workaround" I can come up with involves the following:
- close the channel
- rename the file (maybe use the createTempFile method)
- call deleteOnExit on the renamed File object

... maybe this permits renaming to a different storage
device, which might keep local disk utilization to a minimum.


Submitted On 11-APR-2006
joco
This should really be fixed if you ask me.
Why not give is a close method on the Bufffer. Which does the same as the GC does when it cleans it up
Doing something with deleteOnExit is stupid in myeyes because when does it exit? I can have an op open 8h or even 24h.

this seems a bit of a problem that is on more places like the ClassLoader problem in jar files that also keeps files open... Because UrlConnection doesn't have a disconnect() I do think that these kind of things java is just wrong. Just let me cleanup my mess... Let the GC just cleanup memory anything io related should be closeable for a developer.


Submitted On 02-JUN-2006
Callmeier
This should really be fixed. It makes memory mapped IO unusable for real-world projects.


Submitted On 17-JUL-2006
Please change the affected Java VM's list to 1.5 - it is still there on build 1.5.0_07-b03 for Windows.


Submitted On 10-DEC-2007
maslyak
So "Write once, run anywhere" not works :(


Submitted On 04-MAR-2008
Abhiruka
The only way i founed  was to put the data into a byte array and convert it back to a ByteBuffer. 


Submitted On 11-AUG-2008
Yubin_Z
A work around: you can unmap by clean method of class, then delete. See below.
public void unmap(final Object buffer) throws Exception {
	       AccessController.doPrivileged(new PrivilegedAction() {
	public Object run() {
	try {
			Method getCleanerMethod = buffer.getClass()

	                                .getMethod("cleaner", new Class[0]);

		               getCleanerMethod.setAccessible(true);
		               
		               sun.misc.Cleaner cleaner = (sun.misc.Cleaner) 

	                               getCleanerMethod.invoke(buffer, new Object[0]);

		               cleaner.clean();

	} catch (Exception e) {
		             e.printStackTrace();

	}
	return null;

	}
	       }); 
	 }



PLEASE NOTE: JDK6 is formerly known as Project Mustang