Добрый день всем,
Меня учили, что когда функция возвращается, переменные (в рамках этой функции) автоматически выходят из области видимости, поэтому нам не нужно устанавливать их в null.
Однако, похоже, это не так.
У меня есть тестовый код, который создает java.lang.ref.PhantomReference , указывающий на экземпляр java.lang.Object . Единственная сильная ссылка на этот объект находится в пределах функции F.
Другими словами, когда эта функция возвращается, больше не должно быть сильной ссылки на этот объект, и объект должен теперь быть собран GC.
Однако, как бы я ни старался из-за недостатка памяти JVM, GC просто отказывается собирать объект. Что удивительно, так это то, что если я установил переменную в null (obj = null;
), GC теперь собирает объект.
Чем объясняется эта странность?
public class Test {
public static void main(String args[]) {
// currently testing on a 64-bit HotSpot Server VM, but the other JVMs should probably have the same behavior for this use case
Test test = new Test();
test.F(new Object());
}
public <T> void F(T obj) {
java.lang.ref.ReferenceQueue<T> ref_queue = new java.lang.ref.ReferenceQueue<T>();
java.lang.ref.PhantomReference<T> ref = new java.lang.ref.PhantomReference<T>(obj, ref_queue); // if this line isn't an assignment, the GC wouldn't collect the object no matter how hard I force it to
obj = null; // if this line is removed, the GC wouldn't collect the object no matter how hard I force it to
StartPollingRef(ref_queue);
GoOom();
}
private <T> void StartPollingRef(final java.lang.ref.ReferenceQueue<T> ref_queue) {
new java.lang.Thread(new java.lang.Runnable() {
@Override
public void run() {
System.out.println("Removing..");
boolean removed = false;
while (!removed) {
try {
ref_queue.remove();
removed = true;
System.out.println("Removed.");
} catch (InterruptedException e) { // ignore
}
}
}
}).start();
}
private void GoOom() {
try {
int len = (int) java.lang.Math.min(java.lang.Integer.MAX_VALUE, Runtime.getRuntime().maxMemory());
Object[] arr = new Object[len];
} catch (Throwable e) {
// System.out.println(e);
}
}
}