0

pleaes refer to the following code, i just want to do something about unsafe.

import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.*;

public class A {

    public static void main(String[] args) throws Exception {
        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe u = (Unsafe) f.get(null);
        System.out.println("the while start at:" + new Date());
        long total = 0;
        while (true) {
            u.allocateInstance(B.class);
            total++;
            if (total % 100000000 == 0) {
                System.out.println(total);
                System.gc();
            }
        }
    }
}

class B {

    private int a;
    private int b;
    private double d;
    private float e;

    @Override
    protected void finalize() {
        try {
            super.finalize();
        } catch (Throwable e) {
            System.out.println("catch excep");
        }
        System.out.println("class B finalize, the a:" + a);
    }
}

the code is never oom, but the finalize of class B is never called.why? i can not find the key information....

yaoweijq
  • 263
  • 2
  • 12
  • Looks like finalizers are only registered when you call the constructor. See [this comment](https://stackoverflow.com/questions/48616630/is-it-possible-to-call-constructor-on-existing-instance#comment84254148_48621266). – shmosel Apr 02 '19 at 02:51

1 Answers1

1

This OpenJDK thread notes the following:

Unsafe.allocateInstance() is implemented in HotSpot VM by directly calling JNI's AllocObject() function [1]. An object instance is allocated in the Java heap, but no constructors are invoked for this instance.

Furthermore, the Java Langauge Specification (§12.6.0) specifically states that:

The completion of an object's constructor happens-before (§17.4.5) the execution of its finalize method (in the formal sense of happens-before).

Given that in your code you never actually call the constructors for the allocated instances, the Object.finalize() method cannot be called without first violating the aforementioned happens-before order (§17.4.5).

Therefore, the Object.finalize() method will never be called.

RlonRyan
  • 607
  • 1
  • 4
  • 19
  • It is also worth noting that calling `System.gc()` merely *suggests* that the garbage collector is run (as per the [Java Documentation for the System Class](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#gc())), and does not guarantee it is even run at all. – RlonRyan Apr 02 '19 at 05:45
  • 1
    I think you're misapplying the *happens-before* guarantee. Consider that "An unlock on a monitor *happens-before* every subsequent lock on that monitor." Does that mean you can't lock a monitor without a prior unlock? Obviously not, because monitors are unlocked by default. *Happens-before* only establishes an ordering between two given actions. If there's only one action, the guarantee doesn't exist to begin with. – shmosel Apr 04 '19 at 07:34
  • @shmosel you are right, the *happens-before* relationship doesn’t say anything about this constraint, which, however, truly exist. It has been specified in [JLS §12.6.1. Implementing Finalization](https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.6.1-330): “*An object `o` is not finalizable until its constructor has invoked the constructor for `Object` on `o` and that invocation has completed successfully (that is, without throwing an exception)*”. That’s what this answer should cite. – Holger Apr 04 '19 at 13:11