【发布时间】:2018-03-20 09:57:53
【问题描述】:
我正在尝试创建一种机制来将对象缓存到内存中,以备将来使用,即使这些对象脱离上下文也是如此。将有一个并行的确定性过程,它将(通过唯一的 ID)指示缓存的对象是否应该再次检索或是否应该完全死亡。这是最简单的示例,带有调试信息以使事情变得更容易:
package com.panayotis.resurrect;
import java.util.Map;
import java.util.HashMap;
public class ZObject {
private static int IDGEN = 1;
protected int id;
private boolean isKilled = false;
public static final Map<Integer, ZObject> zombies = new HashMap<>();
public static void main(String[] args) {
for (int i = 0; i < 5; i++)
System.out.println("* INIT: " + new ZObject().toString());
gc();
sleep(1000);
if (!zombies.isEmpty())
ZObject.revive(2);
gc();
sleep(1000);
if (!zombies.isEmpty())
ZObject.kill(1);
gc();
sleep(1000);
gc();
sleep(1000);
gc();
sleep(1000);
gc();
sleep(1000);
}
public ZObject() {
this.id = IDGEN++;
}
protected final void finalize() throws Throwable {
String debug = "" + zombies.size();
String name = toString();
String style;
if (!isKilled) {
style = "* Zombie";
zombies.put(id, this);
} else {
style = "*** FINAL ***";
zombies.remove(id);
super.finalize();
}
dumpZombies(style + " " + debug, name);
}
public String toString() {
return (isKilled ? "killed" : zombies.containsKey(id) ? "zombie" : "alive ") + " " + id;
}
public static ZObject revive(int peer) {
ZObject obj = zombies.remove(peer);
if (obj != null) {
System.out.println("* Revive " + obj.toString());
obj.isKilled = false;
} else
System.out.println("* Not found as zombie " + peer);
return obj;
}
public static void kill(int peer) {
int size = zombies.size();
ZObject obj = zombies.get(peer);
String name = obj == null ? peer + " TERMINATED " : obj.toString();
zombies.remove(peer);
dumpZombies("* Kill " + size, name);
if (obj != null)
obj.isKilled = true;
}
private static void dumpZombies(String baseMsg, String name) {
System.out.println(baseMsg + "->" + zombies.size() + " " + name);
for (Integer key : zombies.keySet())
System.out.println("* " + zombies.get(key).toString());
}
public static void gc() {
System.out.println("* Trigger GC");
for (int i = 0; i < 50; i++)
System.gc();
}
public static void sleep(int howlong) {
try {
Thread.sleep(howlong);
} catch (InterruptedException ex) {
}
}
}
这段代码将创建 5 个对象,复活第一个,然后杀死第一个。我期待着
第一次复活后,由于对象还没有任何引用,通过 finalize 重新进入僵尸状态(它没有)
再次杀死一个对象后,再次通过finalize方法从内存中完全删除
换句话说,finalize 似乎只被调用了一次。我用这段代码检查了这不是 HashMap 对象的副产品:
package com.panayotis.resurrect;
import java.util.HashMap;
public class TestMap {
private static final HashMap<Integer, TestMap> map = new HashMap<>();
private static int IDGEN = 1;
private final int id;
public static void main(String[] args) {
map.put(1, new TestMap(1));
map.put(2, new TestMap(2));
map.put(3, new TestMap(3));
map.remove(1);
System.out.println("Size: " + map.size());
for (int i = 0; i < 50; i++)
System.gc();
}
public TestMap(int id) {
this.id = id;
}
protected void finalize() throws Throwable {
System.out.println("Finalize " + id);
super.finalize();
}
}
那么,为什么会有这种行为?我正在使用 Java 1.8
编辑由于这不可能直接实现,有什么想法可以做到这一点吗?
【问题讨论】:
-
根据您对我的回答的回复,这似乎是XY Problem
-
“由于这不可能直接实现,有什么想法我可以做到这一点吗?” - IMO,你需要清楚地解释“这个”到底是什么。
-
我将创建一个新问题,谢谢提及
标签: java memory-management garbage-collection jvm