1

在 Java 中,有一个嵌套的静态类Human,我想知道在清理map变量后是否可以使其可用于垃圾收集。就在doSomeCode()我打电话System.gc()并添加Thread.sleep(60000)以等待垃圾收集器拾取未引用的map内容之前的那一刻,但没有办法 - 它似乎map存在于程序中,除非它即将完成。我的问题是我需要释放内存,否则会得到OutOfMemoryError.

你认为是什么阻止map了阶级的财产Human被回收?是因为Human类是静态的,因此它的所有成员都不能被垃圾收集吗?

import java.util.List;
import java.util.ArrayList;
import com.carrotsearch.hppc.IntObjectMap;
import com.carrotsearch.hppc.IntObjectOpenHashMap;

public class TestNestedStaticClass {

    public static class Human {

        String name = null;

        List<Human> children = null;

        // some data about family members
        IntObjectMap<int[]> map = null;

        public Human(String name) { this.name = name; }

    }

    public static void main(String[] args) {

        final List<Human> family = new ArrayList<Human>();
        for (int i = 0; i < 1000; i++) {    

            // create and get the family member
            family.add(new Human("givenName"));
            Human h = family.get(i);

            // create map and add some data
            h.map = new IntObjectOpenHashMap<int[]>();
            for (int j = 0; j < 100; j++) {
                int[] array = new int[1500];
                h.map.put(j, array);
            }

        }

        // ...

        // at some point we want to free the memory occupied by
        // family.get(i).map for all i from 0 to 1000, so we do:
        for (int i = 0; i < 1000; i++) {

            // get the family member
            Human h = family.get(i);

            // explicitly remove references from the map
            for (int j = 0; j < 100; j++) {
                h.map.remove(j);
            }

            // cleanup
            h.map.clear();
            h.map = null;

        }

        // ...

        doSomeCode();

    }

}
4

6 回答 6

3

从您编写: 的那一刻起h.map = null;,该地图就符合 GC 条件(从技术上讲,删除和清除不是必需的)。

您看不到它被 GC 处理的原因可能是因为您在同一方法中运行所有代码,并且 GC 在方法退出之前不必收集局部变量。

如果您尝试将其拆分为多个方法,它将有助于 GC(一旦方法退出,它将摆脱局部变量)。

另见这篇文章

ps:我假设您在其他任何地方都没有对地图内容或地图本身的任何引用!

于 2013-04-15T17:53:19.787 回答
2

Human 类是静态的这一事实没有任何意义——即使map变量是静态的,将其设置为 null 也会释放对象内容以进行垃圾收集。

如果您遇到 OutOfMemoryErrors,并且您确定地图内容是原因,那么一定存在对某处数据的挥之不去的引用。例如,如果我这样做:

human.map.put(0, new int[10000]);
something.thing = map.get(0);
human.map.remove(0);
human.map = null;

请注意,对int[10000]仍保留在内存中的引用 @ something.thing。清理地图只是释放数组以进行垃圾收集所需的工作的一部分。

于 2013-04-15T17:53:04.040 回答
0

请注意,内部static类确实是顶级类,但只是在 a 内部class,因此收集其实例的 GC 规则与 GC 应用于公共类实例的规则相同。

于 2013-04-15T17:52:13.107 回答
0

之后不需要休眠System.gc()- gc 方法在垃圾收集器完成之前不会返回。

出于垃圾收集的目的,静态内部类的实例被视为与任何其他类的实例相同。您正确地释放了mapHuman 类的元素(尽管调用map.remove()andmap.clear()map = null- 只是map = null需要)

于 2013-04-15T17:55:04.820 回答
0

看起来您正在使用所有原始数据类型。这可能是一个问题,这只是一个理论,我还没有测试过,但它可能值得一试。

尝试使用 ArrayList,而不是使用 int 数组 ( int[] )。这应该创建可以被垃圾收集的对象,原始数据类型是在堆栈上而不是在对象堆上创建的,因此它们不受垃圾收集的影响?

注意:我打了一个问号,因为我不肯定,有人可以确认或拒绝我的理论。

理论被拒绝:(,留给其他人阅读

于 2013-04-15T18:02:22.960 回答
-3

1)自从我用Java编程以来已经有一段时间了,但我的猜测是静态对象/变量在程序的整个执行过程中都存在于一个特殊的地方。

2) 显式调用 GC 并不能确保对象将被删除。您只需调用 GC,它就会自行决定(并且您不能真正影响此行为)。

于 2013-04-15T17:49:44.577 回答