How to prevent an object from getting garbage coll

2019-01-10 18:58发布

How to prevent an object from getting garbage collected?

Are there any approaches by finalize or phantom reference or any other approaches?

I was asked this question in an interview. The interviewer suggested that finalize() can be used.

10条回答
来,给爷笑一个
2楼-- · 2019-01-10 19:44

This sounds like one of those interview-only-time-you'll-see-it questions. finalize() is run when your object is getting garbage collected, so it'd be pretty perverse to put something in there to prevent collection. Normally you just hold a reference and that's all you need.

I'm not even sure what would happen if you'd create a new reference for something in the finalizer - since the garbage collector's already decided to collect it would you then end up with a null ref? Seems like a poor idea, in any case. e.g.

public class Foo {
   static Foo reference;
  ...
  finalize (){ 
     reference = this; 
  }
}

I doubt this would work, or it might work but be dependant on the GC implenetation, or be "unspecified behavior". Looks evil, though.

查看更多
【Aperson】
3楼-- · 2019-01-10 19:44

The key point is if we set the real reference variable pointing to the object null,although we have instance variables of that class pointing to that object not set to null. The object is automatically eligible for garbage collection.if save the object to GC, use this code...

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);


    }

}

Output :

In finalize method.
In finalize :ID :1001
In finalize :ID :Praveen

------- After called GC () --------

Id :1001
Name :Praveen

查看更多
啃猪蹄的小仙女
4楼-- · 2019-01-10 19:49

I wonder if what they're going for is the pattern with resource pools (e.g. for network/db connections, or threads) where you use finalize to return a resource to the pool so that the actual object holding the resource isn't GC'ed.

Stupid example, in Java-like pseudocode and missing any kind of synchronization:

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();
    }
}
查看更多
混吃等死
5楼-- · 2019-01-10 19:50

The best way is to use Unsafe, although ByteBuffer might be a possible workaround for some cases.

Also search for the keyword "off-heap" memory.

Unsafe

Advantages over ByteBuffer:

  • allows objects to be represented directly, without for serialization and thus faster
  • no bounds checking, so faster
  • explicit deallocation control
  • can allocate more than the JVM limit

It is not however easy to get working. The method is described in the following articles:

They all consist of the following steps:

  • we need a sizeof operator, which Unsafe does not have. How to make one was asked at: In Java, what is the best way to determine the size of an object?. The best options is likely the instrument API, but that requires you to create a Jar and use special command line options...

  • once we have sizeof, allocate enough memory with Unsafe#allocateMemory, which is basically a malloc and returns an address

  • create a regular on heap object, copy it to the allocated memory with Unsafe#copyMemory. To do this, you need to the address of the on-heap object, and the size of the object

  • set an Object to point to the allocated memory, then cast the Object to your class.

    It does not seem possible to set the address of a variable directly with Unsafe, so we need to wrap the object into an array or wrapper object, and use Unsafe#arrayBaseOffset or Unsafe#objectFieldOffset.

  • once you are done, free the allocated memory with freeMemory

If I ever get this to not segfault I will post an example :-)

ByteBuffer

Advantages over Unsafe:

  • stable across Java versions while Unsafe may break
  • does bound checking, so safer than... Unsafe, which allows for memory leaks and SIGSEGV

JLS says:

The contents of direct buffers may reside outside of the normal garbage-collected heap.

Example of usage with primitives:

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;

Related threads:

查看更多
登录 后发表回答