我对垃圾收集器如何在Java中工作有一个大概的概念,但我推销对象的原因不是因为我关心释放内存,而是因为功能。我可以通过一个例子更好地解释:
说我正在制作一个涉及金钱的游戏。当一个人从地面拿起Money
个对象时,我想调用该对象的addTo
方法,该方法涉及为该人的钱包添加值。
public class Money {
/** The value of this object. */
private final int value;
// constructor
public Money(double x) {
this.value = x;
}
// Should be called when a Person picks up this object.
public void addTo(Person bob) {
bob.addToWallet(this.value);
}
// MAIN METHOD
public static void main(String[] args) {
Person bob = new Person();
Money dollar = new Money(1.00);
dollar.addTo(bob); // bob finds $1.00
}
}
找到dollar
后,我不希望别人能够接听它。换句话说,我不希望自己或任何其他程序意外地调用该行:
dollar.addTo(alice);
所以在鲍勃拿到钱之后,它的价值被添加到他的钱包中,不再需要该值的对象表示了。这不是我关心对象使用的内存,但我不希望该对象在程序中的其他地方被意外使用。除了设置dollar
之外,我如何销毁dollar = null;
?
答案 0 :(得分:3)
你根本不应该考虑垃圾收集。由JVM决定什么时候可以进行垃圾收集,99%的时间,如果你负责任地编程,你根本不需要考虑这个。
回答我这个问题......“该对象会如何在程序中的其他地方被意外使用”?
答案是,它不可能。本地引用存在,直到主方法结束,不再存在。除非您存储对它的引用,否则无法引用它。
随着程序的增长,暂时存储对它的引用可能是个好主意。你需要用一个对象来表示你的“地面”的概念。由于您描述的功能是基本的,因此您可以使用Collection
的任何内置实现,例如List
。
List<Money> floorMoney = new LinkedList<Money>();
floorMoney.add(new Money(1.00));
当你将地板上的钱与Person
联系起来时,你会把它从地板上移走。
Money dollar = floorMoney.get(0); // how you access elements may vary
floorMoney.remove(dollar);
dollar.addTo(bob);
现在,除非您在dollar
实施中的某处存储对addTo
的引用,否则Money
对象将被放弃,之后将被GC。
答案 1 :(得分:3)
如果您真的想尽可能地模拟现实世界,可以在美元中添加所有者属性,这样当您调用dollar.addTo()时,您将不得不更改所有者,仅限美元在任何特定时间属于一个人。
答案 2 :(得分:1)
dollar=null
会做到这一点。通过消除对该对象的引用,无法引用该对象。垃圾收集器与此无关。
这样想一想:如果你不想让别人来你家,你就不必炸毁你的房子。只是不要给他们地址。幸运的是,对象无法跟踪其他物体,就像疯狂的前女友一样,可以跟踪那些倾倒她的人......在工作之外停车,随时发送短信,给父母打电话......
哦,对不起,回到你的问题。
如果地面是某种Collection
(例如List
),那么从地面收集中移除这些钱也会使其远离其他玩家或流氓有感知的物体。< / p>
如果你的钱也是Object
有价值,那么在挑选第一个玩家后,你可以将其值设置为-1000,从而惩罚那些明显不属于他们的人。
答案 3 :(得分:1)
您对Java垃圾收集-GC-有无控制,现在您可以强制Java虚拟机为您销毁对象。
您可以调用System.gc()
[或Runtime.getRuntime().gc()
]但这只是建议JVM运行垃圾收集。确实,JVM不应该为此倾听,并且 GC执行无法保证。不要依赖它。
关于您的设计需求,将您的钱存入银行(或街道,如果您希望人们找到它们)并要求银行给您一个。假设银行只有1,那么后续的调用将返回null。
DOWNVOTE后编辑
我决定从我的书中删除一些灰尘,并引用SCJP学习指南第3章中强制垃圾收集部分的几行内容。我为纯粹的受虐狂而研究过的一本书。
这里应该提到的第一件事是,与本节的标题相反,不能强制进行垃圾收集。
..建议您永远不要在代码中调用System.gc() - 将其留给JVM。
..只能向JVM建议它执行垃圾收集。但是,无法保证JVM实际上会从内存中删除所有未使用的对象(即使运行垃圾收集)。
垃圾收集是一个比看起来更难的概念......
答案 4 :(得分:1)
作为@pstanton所说的扩展,保留自有对象的集合。这是一种精心设计的方法,可用于防止错误的代码破坏您的状态。
public abstract class Possession {
private Object _key = null;
public synchronized Object acquire() {
if (_key != null) { throw new IllegalStateException(); }
_key = new Object();
}
public synchronized void release(Object key) {
if (_key != key) { throw new IllegalStateException(); }
_key = null;
}
}
public class Possessions implements Iterable<Possession> {
private final Map<Possession, Object> _possessions = new IdentityHashMap<...>();
public synchronized void add(Possession p) {
if (!_possessions.containsKey(p)) {
_possessions.put(p, p.acquire());
}
}
public synchronized void remove(Possession p) {
Object key = _possessions.remove(p);
if (key != null) {
p.release(key);
}
}
public Iterator<Possession> iterator() {
return Collections.unmodifiableSet(_possessions.keySet()).iterator();
}
}
public class Money extends Possession { ... }
public class Person {
private final Possessions _possessions = new Possessions();
public void add(Money money) {
_possessions.add(money);
}
}
答案 5 :(得分:0)
你只需要避免让“美元”可用于你不想去的地方。 请注意,这不是GC问题。对于非GC环境(如C ++),如果某人看到指向已删除对象的指针,则会在尝试访问它时崩溃并刻录。
答案 6 :(得分:0)
为什么你不能添加布尔“挑选”默认值= false?或创建一个列表并从中删除?
答案 7 :(得分:0)
虽然定义所有权(以Money
s集合,钱包作为集合,或者所有者属性为金钱)可能在理论上是更清晰的解决方案,但我可以很容易地想象当这是过度杀伤时的情况。
例如,人们拿走他的钱可能完全无关紧要。一旦获得金钱,游戏就不关心谁拥有Money
我建议只添加isPicked
属性:
public class Money {
private final int value;
private boolean _isPicked = false;
public Money(double x) {
this.value = x;
}
public boolean isPicked(){
return _isPicked;
}
public void addTo(Person bob) {
if( this.isPicked )
throw new Exception("some message for developers");
bob.addToWallet(this.value);
_isPicked = true;
}
public static void main(String[] args) {
Person bob = new Person();
Money dollar = new Money(1.00);
dollar.addTo(bob); // bob finds $1.00
// dollar = null; // don't need this anymore
Person alice = new Person();
dollar.addTo( alice ); // <------ RUNTIME EXCEPTION
}
}
执行dollar = null
也会导致异常,但它不太安全,因为您可能只是忘记这样做,或者意外地将引用复制到另一个变量