System.gc()调用 - 适用的场景
一、System.gc()调用
System.gc()用于调用垃圾收集器,在调用时,垃圾收集器将运行以回收未使用的内存空间。它将尝试释放被丢弃对象占用的内存。然而System.gc()调用附带一个免责声明,无法保证对垃圾收集器的调用。我们习惯了从现实世界的经验中获得的“条件适用”。一切都附有免责声明!
JVM实现者可以通过System.gc()调用来决定JVM的行为。一般来说,我们在编写Java代码并将其留给JVM时,不要考虑内存管理。在一些特殊情况下,如我们正在编写一个性能基准,我们可以在运行之间调用System.gc()。以下是调用gc有所作为的另一个例子。
二、MappedByteBuffer与System.gc()
MappedByteBuffer用于需要最佳IO性能的地方。MappedByteBuffer提供到底层文件的直接内存映射。
API Javadoc说,
内存映射文件的许多细节固有地依赖于底层操作系统,因此是未指定的。当请求的区域未完全包含在该通道的文件中时,此方法的行为是未指定的。对该程序或另一个的底层文件的内容或大小进行的更改是否被传播到缓冲区是未指定的。没有指定将缓冲区的更改传播到文件的速率。
几乎所有的东西都是未指定的,并留给底层操作系统。我们来看下面的代码:
package com.javapapers.java; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class MappedFileGc { public static void main(String[] args) throws IOException { File tempFile = File.createTempFile("Temp", null); tempFile.deleteOnExit(); RandomAccessFile raTempFile = new RandomAccessFile(tempFile, "rw"); FileChannel fChannel = raTempFile.getChannel(); MappedByteBuffer mappedBuffer = fChannel.map( FileChannel.MapMode.READ_WRITE, 0, 512); fChannel.close(); raTempFile.close(); mappedBuffer = null; System.gc(); if (tempFile.delete()) System.out.println("Successfully deleted: " + tempFile); else System.out.println("Unable to delete: " + tempFile); } }
在上面的代码中,行号24 System.gc()被注释。当我现在运行这个程序,总是得到“ Unable to delete: … ”。现在可以取消注释System.gc()并重新运行它多次以了解行为。现在我们得到“Successfully deleted: …”。大部分时间,我测试的与ByteBuffer相同,垃圾收集立即发生。
相似的,因为MappedByteBuffer依赖于操作系统,垃圾收集器不能立即回收。但是当我们调用System.gc()垃圾收集器释放句柄,我们可以删除该文件。推荐一下,“在使用MappedByteBuffer的同时,如果我们正在使用内存敏感程序,那么最好调用System.gc()”。请注意,此行为依赖于JVM。