我是一名进入Java世界的C ++程序员.而且,我不能删除必须让Java垃圾收集器进行清理的不良感觉。
例如,此代码将如何在Java中运行?
public void myFunction() {
myObject object = new myObject();
object.doSomething();
}
当myFunction()退出时,是否将删除局部变量对象?
我是否必须在退出之前将对象设置为null,否则它将超出范围并被GC删除吗? 或者,在最坏的情况下,它会像在C ++中那样泄漏吗?
- 2021-1-111 #
- 2021-1-112 #
GC至少在内存限制接近时才开始工作,因为超出范围的变量引用的任何对象都可以被垃圾回收, 但是最后一个退出的块存在超出范围的局部变量的意外行为。
让我们来比较一下:
{ final List myTooBigList = new ArrayList(); ... overfill the list } somethingRunOutOfMemory();
somethingRunOutOfMemory()
因为myTooBigList
不能使用GC,尽管范围不再可用,并且要求更多的内存,与以下不同:{ final List myTooBigList = new ArrayList(); ... overfill the list } Object fake = null; somethingDoesNotRunOutOfMemory();
对
fake
的影响 向后移动堆栈指针,让myTooBigList
GCable,然后只要内存限制接近,GC就会开始工作。 令人惊讶的是(至少在我正在测试的jvm中),我们必须在同一级别上显式地重用堆栈.可以预料到,一旦退出该块,局部变量就可以被GC使用,但是我认为这是对性能的一种折衷.这样会使字节码复杂得多。像C中一样,局部变量位于框架旁边的堆栈中。 堆栈指针为范围内的局部变量保留所需的空间。 重用堆栈时,{退出块}的局部变量变为GCable,即:在同一堆栈级别上声明局部变量之后,函数返回之后或退出评估(捕获,循环条件)之后。
在:之后它们是可GC使用的
try { } catch : after exit by catch because catch reuses stack for { } : after exit loop condition because evaluation reuses stack while { } : after exit loop condition because evaluation reuses stack { } declare=value : after any declaration+affectation that reuses stack
在:之后它们不能被GC使用
try { } : after nothing caught for { } : after exit by break while { } : after exit by break do { } if { } { }
注意:要进行实验,请运行GC,然后比较
WeakReference(my variable)
到null
final WeakReference gctest; { final List myTooBigList = new ArrayList(); gctest = new WeakReference(myTooBigList); ... overfill the list } Object fake = null; System.gc(); assert gctest.get() == null;
- 2021-1-113 #
它将超出范围.在Java中,当没有人再指向一个对象时,该对象将被垃圾回收,或者至少可用于垃圾回收.无需在此处将其设置为null.有时,如果您的对象将存在于您的App中,则需要将对象引用设置为null,但是需要对其进行保存的引用进行垃圾收集.在这种情况下,您选择释放参考。
在不再使用后的某个时候,它将在处被垃圾回收.我相信在Java的当前实现中,它实际上将一直保留到方法结束时,而.NET中的垃圾收集器则更具攻击性. (即使在Java中,我也不知道是否有任何保证。通常,您只想想要在调试时将本地变量保留到其上次可能读取的范围之外。)
但是不,您不需要将变量设置为null,否则会损害可读性。
方法退出后,对象不太可能立即立即进行垃圾回收; 这取决于GC的运行时间……而且,当然,如果有任何其他保留该对象的引用,则该对象可能仍不适合进行垃圾收集.不要忘记变量的值只是一个引用,而不是对象本身. (这可能需要一段时间才能习惯于C ++。)