清除或设置null到java中的对象

我最近正在考虑释放Java对象占用的内存。 在这样做时,我对如何在Java中复制(浅/深)对象以及如何避免在对象仍处于使用状态时意外清除/无效而感到困惑。

请考虑以下方案:

  1. ArrayList作为参数传递给方法。
  2. ArrayList传递给可由线程处理的可运行类。
  3. ArrayList放入HashMap

现在在这种情况下,如果我调用list = null;list.clear(); ,对象会发生什么? 在这种情况下,对象会丢失,在哪种情况下只将引用设置为null?

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

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

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

 ArrayList list1 = new ArrayList(); ArrayList list2 = list1; 

……在这个意义上,不做浅拷贝或深拷贝。 它只是复制参考。 在上面的代码之后, list1list2是独立变量 – 它们恰好恰好具有相同的值(引用)。 我们可以改变其中一个的值,它不会影响另一个:

 list1 = null; System.out.println(list2.size()); // Just prints 0 

现在,如果不是更改变量 ,而是对变量值引用的对象进行更改,那么更改也将通过另一个变量可见:

 list2.add("Foo"); System.out.println(list1.get(0)); // Prints Foo 

回到原来的问题 – 你永远不会将实际对象存储在地图,列表,数组等中。您只能存储引用 。 当没有“实时”代码到达该对象的方式时,对象只能被垃圾收集。 所以在这种情况下:

 List list = new ArrayList(); Map> map = new HashMap>(); map.put("Foo", list); list = null; 

ArrayList对象仍然无法进行垃圾回收,因为Map有一个引用它的条目。

清除变量

据我所知,

如果要重用该变量,请使用

  Object.clear(); 

如果您不打算重用,那么定义

  Object=null; 

注意:与removeAll()相比,clear()更快。

请纠正我,如果我错了……

这取决于有多少变量引用到每个对象,为了解释这一点,一些代码会更好:

 Object myAwesomeObject = new Object(); List myList = new ArrayList(); 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. 

因此,它不依赖于您是否将ArrayList作为参数传递给方法等,它取决于仍然有多少变量引用您的对象。

如果将列表放入哈希映射中,则哈希映射现在包含对列表的引用。

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

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

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

如果你只是清除列表,引用仍然有效,但现在将指向一个突然被清空的列表,程序员可能不知道这可能被认为是一个错误,特别是如果你使用该线程。

如果您将一个ArrayList传递给一个方法,那么如果在某个地方存在对该列表的实时引用,例如在调用代码中,则list = null将不起作用。 如果在代码中的任何位置调用list.clear(),则对此列表中对象的引用将为空。 传递方法的引用并不浅,它传递引用的按值

Java GC在任何地方未被引用时自动声明对象。 因此,在大多数情况下,您必须明确地将引用设置为null

一旦变量的范围结束,对象就有资格获得GC,并且如果没有其他引用指向该对象,则会释放该对象。

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

 public class A{ private List list = new ArrayList(); 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 list){ list = null; //just this reference is set to null and not the original one //so list of A will not be GCed } } 

我最近正在考虑释放java对象占用的内存。

一个忠告。

考虑这一点通常是一个坏主意 。 尝试“帮助”通常是一个更糟糕的主意。 在99.8%的情况下,Java垃圾收集器能够更好地收集垃圾,如果你实际上只是让它继续使用它……并且不要浪费你的努力来为事物分配null 。 实际上,您正在归零的字段很可能是无论如何都要无法访问的对象。 在这种情况下,GC甚至不会查看您已经填充的字段。

如果你采用这种(实用的)观点,那么你对浅层复制品和深层复制品的所有想法,以及何时可以安全地废弃物品都是没有意义的。


在一小部分情况下,建议指定null …以避免中期或长期存储泄漏。 如果您处于“回收”对象的极少数情况之一实际上是个好主意,那么建议使用归零。