项目中有很多文件删除的代码写的很奇怪。
while(!file.delete())
Thread.sleep(1000);
还有
System.gc();
file.delete();
这个System.gc()导致频繁fgc影响服务性能了。
最终在网上找到说法是因为在windows系统下jdk无法释放已缓存的文件,这是jdk的一个bug
Bug ID: JDK-4715154 (fs) Cannot delete file if memory mapped with FileChannel.map (windows)
里面有两个例子可以测试下,的确不调用System.gc()无法删除文件,所以windows下面要调用System.gc()。那个while循环是怎么回事呢, 他是等jvm内存不足的时候自己触发gc然后释放文件。但是在linux环境下没这个问题,linux环境下就不用调用System.gc()。
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;
// Calling System.gc sometimes works.
// 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();
}
}
}
附
gc日志查看
-
-XX:+PrintGC 输出GC日志
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
-Xloggc:../logs/gc.log 日志文件的输出路径
日志说明:5.617(时间戳): [GC(Young GC) 5.617(时间戳): [ParNew(使用ParNew作为年轻代的垃圾回收期): 43296K(年轻代垃圾回收前的大小)->7006K(年轻代垃圾回收以后的大小)(47808K)(年轻代的总大小), 0.0136826 secs(回收时间)] 44992K(堆区垃圾回收前的大小)->8702K(堆区垃圾回收后的大小)(252608K)(堆区总大小), 0.0137904 secs(回收时间)] [Times: user=0.03(Young GC用户耗时) sys=0.00(Young GC系统耗时), real=0.02 secs(Young GC实际耗时)]
- ->前的是GC前堆内存使用量
- ->后面是GC后堆内存使用量
- 括号内是堆内存总量
- Times: user表示用户态CPU耗时
- sys表示系统CPU耗时
- real表示GC实际耗时
jinfo动态开关
- 开启gc日志
- jinfo -flag +PrintGCDetails pid
- jinfo -flag +PrintGCDateStamps pid
- 关闭gc日志
- jinfo -flag -PrintGCDetails pid
- jinfo -flag -PrintGCDateStamps pid
参考:
Bug ID: JDK-4715154 (fs) Cannot delete file if memory mapped with FileChannel.map (windows)