Java 嵌套静态类的变量可以被垃圾回收吗?

Java 嵌套静态类的变量可以被垃圾回收吗?,java,static,garbage-collection,Java,Static,Garbage Collection,在Java中,有一个嵌套的静态类Human,我想知道清理map变量后,它是否可以用于垃圾收集。就在doSomeCode()之前,我调用了System.gc()并添加了Thread.sleep(60000)以等待垃圾收集器拾取未引用的map内容,但这是不可能的-似乎map存在于程序中,除非它即将完成。我的问题是,我需要释放内存,否则将得到OutOfMemoryError 您认为是什么阻止了map类的Human属性被回收?是因为Human类是静态的,因此不能对其所有成员进行垃圾收集吗 import

在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();

    }

}
import java.util.List;
导入java.util.ArrayList;
导入com.carrotsearch.hppc.IntObjectMap;
导入com.carrotsearch.hppc.IntObjectOpenHashMap;
公共类TestNestedStaticClass{
公共静态类人{
字符串名称=null;
List children=null;
//关于家庭成员的一些数据
InObjectMap map=null;
公共人员(字符串名){this.name=name;}
}
公共静态void main(字符串[]args){
最终列表族=新的ArrayList();
对于(int i=0;i<1000;i++){
//创建并获取家庭成员
添加(新人类(“givenName”);
人类h=家庭。get(i);
//创建地图并添加一些数据
h、 map=新的InObjectOpenHashMap();
对于(int j=0;j<100;j++){
int[]数组=新int[1500];
h、 map.put(j,数组);
}
}
// ...
//在某个时刻,我们想要释放被占用的内存
//从0到1000的所有i的family.get(i).map,因此我们执行以下操作:
对于(int i=0;i<1000;i++){
//找到家人
人类h=家庭。get(i);
//从映射中显式删除引用
对于(int j=0;j<100;j++){
h、 地图.删除(j);
}
//清理
h、 map.clear();
h、 map=null;
}
// ...
doSomeCode();
}
}
1)我用Java编程已经有一段时间了,但我猜在整个程序执行过程中,静态对象/变量都存在于一个特殊的位置


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

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

人类类是静态的这一事实并不意味着什么——即使
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
。清理映射只是释放数组进行垃圾收集所需工作的一部分。

从您写入的地方开始:
h.map=null,则映射符合GC条件(技术上不需要删除和清除)

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

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

另见


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

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


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

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

尝试使用ArrayList,而不是使用int数组(int[])。这应该会创建可以垃圾收集的对象,基本数据类型是在堆栈上而不是在对象堆上创建的,因此它们不受垃圾收集的约束

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


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

静态
与地图为什么没有GC'ed无关。我有点怀疑,
地图
只是在其他东西需要内存之前不会得到GC'd。是的,但我有
OutOfMemoryError
所以确实需要内存。哪一行是
OutOfMemory当我试图在堆上创建更多对象时,在
doSomeCode()
或之前的
doSomeCode()
中发生错误。是的,所有代码都在main中,但我没有像这样显式阻止多个方法,
{}
在不需要映射时使其超出范围。@SophieSperner这可能不够。我将尝试分成几个方法,但如果没有帮助,这意味着垃圾收集不如对象创建快