Java 如何防止对象被垃圾回收?
如何防止对象被垃圾回收 是否有通过最终确定或幻影参考或任何其他方法的方法Java 如何防止对象被垃圾回收?,java,garbage-collection,Java,Garbage Collection,如何防止对象被垃圾回收 是否有通过最终确定或幻影参考或任何其他方法的方法 我在一次采访中被问到这个问题。面试官建议可以使用finalize() 保持一个参考。如果过早收集对象,则表明应用程序的设计存在缺陷 垃圾收集器只收集应用程序中没有引用的对象。如果没有对象会自然引用收集到的对象,请自问为什么它应该保持活动状态 您通常没有引用,但希望保留对象的一个用例是单例。在这种情况下,可以使用静态变量。单例的一个可能实现如下所示: public class Singleton { private st
我在一次采访中被问到这个问题。面试官建议可以使用
finalize()
保持一个参考。如果过早收集对象,则表明应用程序的设计存在缺陷
垃圾收集器只收集应用程序中没有引用的对象。如果没有对象会自然引用收集到的对象,请自问为什么它应该保持活动状态
您通常没有引用,但希望保留对象的一个用例是单例。在这种情况下,可以使用静态变量。单例的一个可能实现如下所示:
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqInstance;
}
}
编辑:从技术上讲,您可以将引用存储在终结器中的某个位置。这将阻止收集对象,直到收集器再次确定不再有引用为止。但是,终结器最多只能调用一次,因此您必须确保对象(包括其超类)在第一次收集后不需要终结。但是,我建议您不要在实际程序中使用此技术。(这会让像我这样的同事大喊WTF!?;)
如果仍然存在对该对象的引用,则不会对其进行垃圾回收。如果没有任何参考资料,你不应该在意
换句话说,垃圾收集器只收集垃圾。让它去做它的工作。我相信这是有规律的。不确定它是否符合工厂模式。但是有一个对象创建了所有对象,并保存了对它们的引用。当您使用完它们后,您将在工厂中取消引用它们,使调用显式。我怀疑您可能指的是,如果您的
finalize
方法隐藏了对正在定稿的对象的引用。在这种情况下(如果我对的读取是正确的),将永远不会重新运行finalize
方法,但对象将不会被垃圾收集
这不是一个人在现实生活中所做的那种事情,除非可能是出于偶然 这听起来像是你唯一一次面试的问题之一。finalize()是在对象被垃圾收集时运行的,所以在其中放入一些东西来防止垃圾收集是非常不正常的。通常你只需要持有一份推荐信,这就是你所需要的 我甚至不确定如果您在终结器中为某个对象创建一个新引用会发生什么-既然垃圾收集器已经决定收集它,那么您会最终得到一个空引用吗?无论如何,这似乎是个糟糕的主意。e、 g
public class Foo {
static Foo reference;
...
finalize (){
reference = this;
}
}
我怀疑这是否有效,或者它可能有效,但取决于GC植入,或者是“未指定的行为”。不过看起来很邪恶。你的面试官想要的答案可能是,他想让你知道,你可以通过强制内存泄漏来防止垃圾收集删除对象 显然,如果您在某个长期存在的上下文中保留对该对象的引用,它将不会被收集,但OP的招聘人员并不是这么问的。这不是finalize方法中发生的事情 要防止finalize方法中的垃圾收集,可以编写一个无限循环,在该循环中调用
Thread.yield()代码>(可能是为了防止空循环被优化):
我在这里的参考文献是作者的一篇文章,其中描述了通过这种方法强制内存泄漏
这只是另一种方式,最终确定方法是邪恶的 关键的一点是,我们是否将指向对象的实际引用变量设置为null,尽管我们没有将指向该对象的类的实例变量设置为null。
该对象自动符合垃圾收集的条件。如果将该对象保存到GC,请使用以下代码
public class GcTest {
public int id;
public String name;
private static GcTest gcTest=null;
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("In finalize method.");
System.out.println("In finalize :ID :"+this.id);
System.out.println("In finalize :ID :"+this.name);
gcTest=this;
}
public static void main(String[] args) {
GcTest myGcTest=new GcTest();
myGcTest.id=1001;
myGcTest.name="Praveen";
myGcTest=null;
// requesting Garbage Collector to execute.
// internally GC uses Mark and Sweep algorithm to clear heap memory.
// gc() is a native method in RunTime class.
System.gc(); // or Runtime.getRuntime().gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\n------- After called GC () ---------\n");
System.out.println("Id :"+gcTest.id);
System.out.println("Name :"+gcTest.name);
}
}
输出:
在最终确定方法中。
在finalize:ID:1001中
在finalize:ID:Praveen中
-------在调用GC()之后--------
Id:1001
名称:Praveen最好的方法是使用,尽管在某些情况下,ByteBuffer
可能是一种可行的解决方法
还要搜索关键字“堆外”内存
不安全
与ByteBuffer相比的优势
:
- 允许直接表示对象,无需序列化,因此速度更快
- 无边界检查,因此速度更快
- 显式释放控制
- 可以分配超过JVM限制的资源
- 我们需要一个
操作符,它没有。如何制作一个在:。最好的选项可能是sizeof
API,但这需要您创建一个Jar并使用特殊的命令行选项工具
- 一旦我们有了
,就用sizeof
分配足够的内存,它基本上是一个safe#allocateMemory
,并返回一个地址malloc
- 创建一个常规堆上对象,使用
将其复制到分配的内存中。为此,需要输入堆上对象的地址和对象的大小safe#copyMemory
- 将
对象设置为指向分配的内存,然后将
对象强制转换为类 似乎不可能直接使用Unsafe设置变量的地址,因此我们需要将对象包装到数组或包装器对象中,并使用
或Unsafe\arraybasecoffset
Unsafe\objectFieldOffset
- 完成后,使用
freemory
@Override
protected void finalize() throws Throwable {
while (true) {
Thread.yield();
}
}
public class GcTest {
public int id;
public String name;
private static GcTest gcTest=null;
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("In finalize method.");
System.out.println("In finalize :ID :"+this.id);
System.out.println("In finalize :ID :"+this.name);
gcTest=this;
}
public static void main(String[] args) {
GcTest myGcTest=new GcTest();
myGcTest.id=1001;
myGcTest.name="Praveen";
myGcTest=null;
// requesting Garbage Collector to execute.
// internally GC uses Mark and Sweep algorithm to clear heap memory.
// gc() is a native method in RunTime class.
System.gc(); // or Runtime.getRuntime().gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\n------- After called GC () ---------\n");
System.out.println("Id :"+gcTest.id);
System.out.println("Name :"+gcTest.name);
}
}
ByteBuffer bb = ByteBuffer.allocateDirect(8);
bb.putInt(0, 1);
bb.putInt(4, 2);
assert bb.getInt(0) == 1;
assert bb.getInt(4) == 2;
// Bound chekcs are done.
boolean fail = false;
try {
bb.getInt(8);
} catch(IndexOutOfBoundsException e) {
fail = true;
}
assert fail;
class SlowResourceInternal {
private final SlowResourcePool parent;
<some instance data>
returnToPool() {
parent.add(this);
}
}
class SlowResourceHolder {
private final SlowResourceInternal impl;
<delegate actual stuff to the internal object>
finalize() {
if (impl != null) impl.returnToPool();
}
}
// Xms specifies initial memory to be allocated
// and Xmx specifies maximum memory can be allocated
java -Xms1024m -Xmx4096m ClassFile
public class MySingletonClass {
private static MySingletonClass uniqueInstance;
// marking constructor as private
private MySingletonClass() {
}
public static synchronized MySingletonClass getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqInstance;
}
}
// using finalize method
class MyClassNotGc{
static MyClassNotGc staticSelfObj;
pubic void finalize() {
// Putting the reference id
//Object reference saved.
//The object won't be collected by the garbage collector
staticSelfObj = this;
}
}