清除java中的对象或将其设置为null

清除java中的对象或将其设置为null,java,memory-management,null,deep-copy,shallow-copy,Java,Memory Management,Null,Deep Copy,Shallow Copy,我最近正在研究如何释放Java对象占用的内存。在这样做的时候,我对Java中如何复制对象(浅/深)以及如何避免在对象仍在使用时意外地清除/取消对象感到困惑 考虑以下情况: 将ArrayList作为参数传递给方法 将ArrayList传递给线程要处理的可运行类 将ArrayList放入HashMap中 现在在这种情况下,如果我调用list=null或列表.清除(),对象会发生什么情况?在哪种情况下,对象丢失,在哪种情况下,只有引用被设置为null 我想这与对象的浅复制和深复制有关,但在哪些情况下会

我最近正在研究如何释放Java对象占用的内存。在这样做的时候,我对Java中如何复制对象(浅/深)以及如何避免在对象仍在使用时意外地清除/取消对象感到困惑

考虑以下情况:

  • ArrayList
    作为参数传递给方法
  • ArrayList
    传递给线程要处理的可运行类
  • ArrayList
    放入
    HashMap
  • 现在在这种情况下,如果我调用
    list=null
    列表.清除(),对象会发生什么情况?在哪种情况下,对象丢失,在哪种情况下,只有引用被设置为null


    我想这与对象的浅复制和深复制有关,但在哪些情况下会发生浅复制,在Java中会发生深复制?

    这取决于引用每个对象的变量数量,为了解释这一点,最好使用一些代码:

    Object myAwesomeObject = new Object();
    List<Object> myList = new ArrayList<Object>();
    
    myList.add(myAwesomeObject);
    
    myList = null; // Your object hasn't been claimed by the GC just yet, your variable "myAwesomeObject" is still refering to it
    
    myAwesomeObject = null; // done, now your object is eligible for garbage collection.
    
    Object myAwesomeObject=new Object();
    List myList=new ArrayList();
    添加(myAwesomeObject);
    myList=null;//您的对象尚未被GC声明,您的变量“myAwesomeObject”仍在引用它
    myAwesomeObject=null;//完成后,现在您的对象可以进行垃圾收集。
    
    因此,这并不取决于是否将ArrayList作为参数传递给方法等,而是取决于仍有多少变量引用对象。

    首先,不要将对象设置为null。这一概念毫无意义。您可以为变量赋值
    null
    ,但需要非常仔细地区分“变量”和“对象”的概念。一旦你这样做了,你的问题就会自动回答:)

    现在,就“浅复制”与“深复制”而言,这里可能值得避免使用“浅复制”一词,因为浅复制通常涉及创建新对象,但只是直接复制现有对象的字段。深度副本还将获取这些字段引用的对象的副本(对于引用类型字段)。这样一个简单的任务:

    ArrayList<String> list1 = new ArrayList<String>();
    ArrayList<String> list2 = list1;
    
    现在,如果不更改变量,而是更改变量值所引用的对象,则该更改也将通过另一个变量可见:

    list2.add("Foo");
    System.out.println(list1.get(0)); // Prints Foo
    
    所以回到你最初的问题——你从来没有在地图、列表、数组等中存储实际对象。你只存储引用。只有当不再有“活动”代码到达对象时,才能对该对象进行垃圾收集。因此,在这种情况下:

    List<String> list = new ArrayList<String>();
    Map<String, List<String>> map = new HashMap<String, List<String>>();
    map.put("Foo", list);
    list = null;
    
    List List=new ArrayList();
    Map Map=newhashmap();
    地图放置(“Foo”,列表);
    列表=空;
    

    。。。
    ArrayList
    对象仍然不能被垃圾收集,因为
    Map
    有一个引用它的条目。

    如果将列表放入哈希映射中,哈希映射现在会保留对列表的引用

    如果将列表作为参数传递给某个方法,则该方法将在该方法的持续时间内对其进行引用

    如果将其传递给要操作的线程,则该线程将拥有对该对象的引用,直到该对象终止

    在所有这些情况下,如果设置
    list=null
    ,引用仍将保持,但在这些引用消失后它们将消失


    如果您只是清除列表,引用仍然有效,但现在将指向一个突然被清空的列表,这可能是程序员不知道的,并且可能被认为是一个bug,特别是在您使用线程的情况下。

    当对象没有被引用到任何地方时,Java GC会自动声明对象。因此,在大多数情况下,您必须显式地将引用设置为
    null

    一旦变量的作用域结束,对象就有资格使用GC,并且如果没有其他引用点指向该对象,该对象就会被释放

    Java是按值传递的,因此如果在方法中将列表设置为
    null
    ,则它不会影响在方法中传递给您的原始引用

    public class A{
    
        private List<Integer> list = new ArrayList<Integer>();
        public static void main(String[] args) {
           A a = new A();
           B b = new B();
    
           b.method(a.list);
    
           System.out.println(a.list.size()); //Will print 0 and not throw NullPointerException
        }   
    
    }
    
    class B{
        public void method(List<Integer> list){
            list = null;
            //just this reference is set to null and not the original one
            //so list of A will not be GCed
        }
    }
    
    公共A类{
    私有列表=新的ArrayList();
    公共静态void main(字符串[]args){
    A=新的A();
    B=新的B();
    b、 方法(a.列表);
    System.out.println(a.list.size());//将打印0而不抛出NullPointerException
    }   
    }
    B类{
    公共作废方法(列表){
    列表=空;
    //仅此引用设置为null,而不是原始引用
    //因此,将不进行GCed
    }
    }
    
    如果将ArrayList传递给方法,则如果调用代码中的某个位置存在对该列表的实时引用,则list=null将无效。如果在代码中的任意位置调用list.clear(),则对该列表中对象的引用将为空。将引用传递给方法不是浅复制,而是按值传递引用

    我最近正在研究如何释放java对象占用的内存

    一条忠告

    考虑这一点通常不是个好主意。而尝试“帮助”通常是一个更糟糕的想法。在99.8%的情况下,Java垃圾收集器能够更好地收集垃圾,如果您真的让它继续进行的话。。。不要把
    null
    分配给对象,浪费精力。实际上,您要为空的字段很可能位于无论如何都将无法访问的对象中。在这种情况下,GC甚至不会查看已为空的字段

    如果你采取这种(务实的)观点,那么你所有关于浅拷贝和深拷贝的想法,以及何时可以安全地为空的想法都是毫无意义的


    建议将
    null
    赋值的情况只占很小的百分比。。。避免中长期储存泄漏。如果您处于“回收”对象实际上是一个好主意的罕见情况之一,那么空值就是一个好主意
    public class A{
    
        private List<Integer> list = new ArrayList<Integer>();
        public static void main(String[] args) {
           A a = new A();
           B b = new B();
    
           b.method(a.list);
    
           System.out.println(a.list.size()); //Will print 0 and not throw NullPointerException
        }   
    
    }
    
    class B{
        public void method(List<Integer> list){
            list = null;
            //just this reference is set to null and not the original one
            //so list of A will not be GCed
        }
    }
    
                   Object.clear();
    
                   Object=null;