为什么Java System.gc()不能按预期工作



下面有两个函数,一个是insert(),另一个是startGC()。

我将首先调用insert()方法,它将占用大约300MB的堆空间。之后,我将调用startGC(),它应该释放堆中分配的内存,因为所有向量对象都是函数的本地对象,但它不会发生。

private void insert()
 {
         Vector v=new Vector();
         Vector v1=new Vector();
         Vector v2=new Vector();
        String str="Hello";
        for (long i = 0L; i < 999999L; i++) {
            v.add(str + i);
            v1.add(str + i);
            v2.add(str + i);
        }
        v=null;
        v1=null;
        v2=null;
 }
private void startGC()
{
    System.gc();
}

我的问题:

1) 为什么垃圾回收在本例中不起作用。

2) 如何让JVM垃圾收集所有未使用的内存块。

任何代码示例都可以实现相同的功能

  1. 它在什么方面不起作用
  2. 您不能告诉JVM启动垃圾回收,只能通过调用System.gc()来建议您认为这是个好主意

来自JavaDoc:

调用gc方法表明,Java虚拟机需要花费精力来回收未使用的对象,以便使它们当前占用的内存可以快速重用。当方法调用返回控制时,Java虚拟机已尽最大努力从所有丢弃的对象中回收空间

如前所述,您只能建议GC删除您的对象。您可以做的唯一一件事就是设置heapmax(例如:-Xmx512m)。您可以通过这种方式影响gc的运行。这可能是Java最大的缺点之一。如果你真的需要堆,你必须使用像cpp这样的语言,它不会使用vm来编译应用程序。

如果我尝试

private static void insert() {
    List<String> v1 = new ArrayList<>(), v2 = new ArrayList<>(), v3 = new ArrayList<>();
    String str = "Hello";
    for (long i = 0L; i <= 999999; i++) {
        v1.add(str + i);
        v2.add(str + i);
        v3.add(str + i);
    }
}
private static void startGC() {
    System.gc();
}
private static long mbUsed() {
    return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024;
}
public static void main(String... args)  {
    startGC();
    System.out.printf("Memory used before insert %,d MB%n", mbUsed());
    insert();
    System.out.printf("Memory used after insert %,d MB%n", mbUsed());
    startGC();
    System.out.printf("Memory used after GC %,d MB%n", mbUsed());
}

它打印

Memory used before insert 2 MB
Memory used after insert 265 MB
Memory used after GC 5 MB

所以它似乎对我有效。

这是一篇关于Java垃圾回收的好文章。

不能强制集合,这是错误的方法。您应该了解可以传递给JVM的不同的垃圾收集参数,并选择能够最大限度地提高您感兴趣的性能的参数(总吞吐量、最小停顿等)。代码本身不应该真正担心gc。

JVM正在回收已分配的内存。

没有必要将其退还给操作系统。

请看一下这篇文章,Java在释放对象和垃圾收集后仍然使用系统内存,这解释了它的工作原理。

最新更新