如果其中一个方法在调用堆栈上,Java 中的垃圾收集器是否会删除对象?
Does the garbage collector in Java remove an object if one of its methods is on the call stack?
一般问题
在Java中,没有指向对象的引用,但该对象的其中一个方法仍在调用堆栈上。
垃圾收集器是否有可能在对象的方法从调用堆栈中弹出之前删除该对象,还是等到方法弹出时才删除?
(请参考下面我的具体问题)
具体问题
Class结构
简单单向链表的实现:
- class 列表:类型 LIST_ELEMENT
的属性 "begin"
- 抽象 class LIST_ELEMENT 具有所有需要的抽象方法
- classes END 和 NODE 继承自 LIST_ELEMENT
- END 没有任何属性,它总是标记列表的结尾
- NODE 的属性是 "next" 类型 LIST_ELEMENT 和 "data" 类型 DATA_ELEMENT
- DATA_ELEMENT 是一个接口,必须由要存储在列表
中的任何 class 实现
LIST 的方法
- insertSorted:插入一个元素,同时保持排序列表的排序
- 排序:先清空列表,再使用insertSorted方法重新插入每个元素,对列表进行排序
代码
public class LIST
{
private LIST_ELEMENT begin = new END();
// some methods to add or remove elements
public void clear()
{
begin = new END();
}
public void insertSorted(DATA_ELEMENT dataNew)
{
begin = begin.insertSorted(dataNew);
}
public void sort()
{
begin.sort(this);
}
}
public abstract class LIST_ELEMENT
{
public abstract LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew);
public abstract void sort(LIST list);
}
public class END extends LIST_ELEMENT
{
@Override
public LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew)
{
return new NODE(this, dataNew);
}
@Override
public void sort(LIST list)
{
list.clear();
}
}
public class NODE extends LIST_ELEMENT
{
private LIST_ELEMENT next;
private DATA_ELEMENT data;
public NODE(LIST_ELEMENT nextNew, DATA_ELEMENT dataNew)
{
next = nextNew;
data = dataNew;
}
@Override
public LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew)
{
if(data.isSmallerThan(dataNew))
{
next = next.insertSorted(dataNew);
return this;
}
else
{
return new NODE(this, dataNew);
}
}
@Override
public void sort(LIST list)
{
next.sort(list);
list.insertSorted(data);
}
}
public interface DATA_ELEMENT
{
public boolean isSmallerThan(DATA_ELEMENT dataCompare);
}
问题
实现了这个排序算法,安全吗?
清除列表后,垃圾收集器能否从 NODE 对象中删除数据(因此调用
list.insertSorted(data);
做了一些意外的事情),或者调用堆栈上的方法是否算作对对象的引用,以便数据属性在 LIST.sort 的整个调用期间有效?
是否保证这段时间内对象不被移除?
在我的测试中,对 LIST.sort 的调用总是按预期对列表进行排序。
In Java, there is no reference pointing to an object, but one of the
methods of this object is still on the call stack.
这不可能发生。如果方法是 运行,则存在对其方法被调用的对象的引用。
Is it possible that the garbage collector removes this object before
its method is popped off the call stack, or does it wait until the
method is popped off?
只要method是运行,就有对象的引用。这就是为什么无法删除此类对象的原因。
看来,您对垃圾收集器的作用有根本性的错误理解。你写了
Can the garbage collector remove the data from the NODE objects after the list was cleared (so the call
list.insertSorted(data);
does something unexpected), or does the method on the call stack count as a reference to the object so that the data attribute is valid for the entire duration of the call of LIST.sort?
Is it guaranteed that the object is not removed during this time?
垃圾收集器永远不会删除 某些东西。删除是应用程序逻辑中的一个操作,例如更改节点对象的 next
字段。垃圾收集器永远不会执行此类操作。
同样,“列表”的语义不会影响垃圾收集器。对于垃圾收集器,您的 LIST
class 的实例只是一个引用另一个对象的对象。当垃圾收集器决定重用 LIST
实例的内存时,它不会影响您可能仍在处理的 LIST_ELEMENT
。它不收集“整个列表”,对于垃圾收集器来说,没有列表这样的东西。
作为一个简单的经验法则,除非你编写的代码与垃圾收集器有特殊的交互,比如终结器或清理器,或者正在处理特殊的弱引用对象、软引用对象或幻引用对象,否则你永远不会注意到垃圾收集器的 activity。它将重用那些应用程序不需要其内存的对象的内存,换句话说,只要您的应用程序不会注意到它。
也就是说,与其他答案相反,执行实例方法不会阻止对未使用的对象进行垃圾回收。但它怎么可能不被使用呢?这意味着即使调用者也没有对该列表的其他引用(或者不会使用它)。那么,如果不存在对列表的引用,谁会关心列表的内容呢?另一种情况是 JVM 优化了代码,因此它不需要对象的内存,例如因为它将所有字段值保存在 CPU 寄存器中。您将再次不会注意到任何东西,因为程序的行为保持不变。
finalize() called on strongly reachable objects in Java 8 中记录了一个现实生活中的示例,其中对象真正完成,而对象的方法调用正在进行中。但如前所述,只有当您与垃圾收集器显式交互时,这些事情才会对应用程序的行为产生可察觉的影响。在链接的问答中,它是一个终结器,产生了明显的效果。
一般问题
在Java中,没有指向对象的引用,但该对象的其中一个方法仍在调用堆栈上。
垃圾收集器是否有可能在对象的方法从调用堆栈中弹出之前删除该对象,还是等到方法弹出时才删除?
(请参考下面我的具体问题)
具体问题
Class结构
简单单向链表的实现:
- class 列表:类型 LIST_ELEMENT 的属性 "begin"
- 抽象 class LIST_ELEMENT 具有所有需要的抽象方法
- classes END 和 NODE 继承自 LIST_ELEMENT
- END 没有任何属性,它总是标记列表的结尾
- NODE 的属性是 "next" 类型 LIST_ELEMENT 和 "data" 类型 DATA_ELEMENT
- DATA_ELEMENT 是一个接口,必须由要存储在列表 中的任何 class 实现
LIST 的方法
- insertSorted:插入一个元素,同时保持排序列表的排序
- 排序:先清空列表,再使用insertSorted方法重新插入每个元素,对列表进行排序
代码
public class LIST
{
private LIST_ELEMENT begin = new END();
// some methods to add or remove elements
public void clear()
{
begin = new END();
}
public void insertSorted(DATA_ELEMENT dataNew)
{
begin = begin.insertSorted(dataNew);
}
public void sort()
{
begin.sort(this);
}
}
public abstract class LIST_ELEMENT
{
public abstract LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew);
public abstract void sort(LIST list);
}
public class END extends LIST_ELEMENT
{
@Override
public LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew)
{
return new NODE(this, dataNew);
}
@Override
public void sort(LIST list)
{
list.clear();
}
}
public class NODE extends LIST_ELEMENT
{
private LIST_ELEMENT next;
private DATA_ELEMENT data;
public NODE(LIST_ELEMENT nextNew, DATA_ELEMENT dataNew)
{
next = nextNew;
data = dataNew;
}
@Override
public LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew)
{
if(data.isSmallerThan(dataNew))
{
next = next.insertSorted(dataNew);
return this;
}
else
{
return new NODE(this, dataNew);
}
}
@Override
public void sort(LIST list)
{
next.sort(list);
list.insertSorted(data);
}
}
public interface DATA_ELEMENT
{
public boolean isSmallerThan(DATA_ELEMENT dataCompare);
}
问题
实现了这个排序算法,安全吗?
清除列表后,垃圾收集器能否从 NODE 对象中删除数据(因此调用
list.insertSorted(data);
做了一些意外的事情),或者调用堆栈上的方法是否算作对对象的引用,以便数据属性在 LIST.sort 的整个调用期间有效?
是否保证这段时间内对象不被移除?
在我的测试中,对 LIST.sort 的调用总是按预期对列表进行排序。
In Java, there is no reference pointing to an object, but one of the methods of this object is still on the call stack.
这不可能发生。如果方法是 运行,则存在对其方法被调用的对象的引用。
Is it possible that the garbage collector removes this object before its method is popped off the call stack, or does it wait until the method is popped off?
只要method是运行,就有对象的引用。这就是为什么无法删除此类对象的原因。
看来,您对垃圾收集器的作用有根本性的错误理解。你写了
Can the garbage collector remove the data from the NODE objects after the list was cleared (so the call
list.insertSorted(data);
does something unexpected), or does the method on the call stack count as a reference to the object so that the data attribute is valid for the entire duration of the call of LIST.sort? Is it guaranteed that the object is not removed during this time?
垃圾收集器永远不会删除 某些东西。删除是应用程序逻辑中的一个操作,例如更改节点对象的 next
字段。垃圾收集器永远不会执行此类操作。
同样,“列表”的语义不会影响垃圾收集器。对于垃圾收集器,您的 LIST
class 的实例只是一个引用另一个对象的对象。当垃圾收集器决定重用 LIST
实例的内存时,它不会影响您可能仍在处理的 LIST_ELEMENT
。它不收集“整个列表”,对于垃圾收集器来说,没有列表这样的东西。
作为一个简单的经验法则,除非你编写的代码与垃圾收集器有特殊的交互,比如终结器或清理器,或者正在处理特殊的弱引用对象、软引用对象或幻引用对象,否则你永远不会注意到垃圾收集器的 activity。它将重用那些应用程序不需要其内存的对象的内存,换句话说,只要您的应用程序不会注意到它。
也就是说,与其他答案相反,执行实例方法不会阻止对未使用的对象进行垃圾回收。但它怎么可能不被使用呢?这意味着即使调用者也没有对该列表的其他引用(或者不会使用它)。那么,如果不存在对列表的引用,谁会关心列表的内容呢?另一种情况是 JVM 优化了代码,因此它不需要对象的内存,例如因为它将所有字段值保存在 CPU 寄存器中。您将再次不会注意到任何东西,因为程序的行为保持不变。
finalize() called on strongly reachable objects in Java 8 中记录了一个现实生活中的示例,其中对象真正完成,而对象的方法调用正在进行中。但如前所述,只有当您与垃圾收集器显式交互时,这些事情才会对应用程序的行为产生可察觉的影响。在链接的问答中,它是一个终结器,产生了明显的效果。