简体   繁体   English

Java直接内存:在自定义类中使用sun.misc.Cleaner

[英]Java direct memory: using sun.misc.Cleaner in custom classes

In Java the memory allocated by NIO direct buffers is freed with sun.misc.Cleaner instances, some special phantom references that are more efficient than object finalization. 在Java中,由NIO直接缓冲区分配的内存通过sun.misc.Cleaner实例释放,一些特殊的幻像引用比对象终结更有效。

Is this cleaner mechanism hardcoded in the JVM only for the direct buffer subclasses, or is it possible to also use cleaners in custom components (writing a custom direct byte buffer for instance)? 这个更清洁的机制是仅在JVM中为直接缓冲区子类进行硬编码,还是可以在自定义组件中使用清理程序(例如编写自定义直接字节缓冲区)?

Here I am not talking about retrieving the cleaner field of an existing nio direct buffer. 在这里,我不是在讨论检索现有nio直接缓冲区的清除字段。 I am not talking either about manually freeing the memory. 我不是在谈论手动释放内存。 This is about writing a new class that allocates direct memory and has it cleaned efficiently and automatically by the garbage collector mechanism. 这是关于编写一个新类,它分配直接内存并由垃圾收集器机制有效地自动清理。

After spending more time reading the API doc ( http://docs.oracle.com/javase/7/docs/api/java/lang/ref/package-summary.html ) I think I have a more detailed answer: 花了更多时间阅读API文档( http://docs.oracle.com/javase/7/docs/api/java/lang/ref/package-summary.html )后,我想我有一个更详细的答案:

1) it is possible to reuse sun.misc.Cleaner to perform the efficient cleanup of your own custom classes. 1)可以重用sun.misc.Cleaner来执行自己的自定义类的高效清理。 You declare the cleaner by calling the provided factory method: 您通过调用提供的工厂方法声明清理器:

sun.misc.Cleaner.create(Object ob, Runnable cleanup);

For some time I could not get it to work properly, that's because I was moronic enough to define the runnable cleanup code of my cleaner as an anonymous class, that kept a (strong) reference to my referent object, preventing it from ever being "phantom reachable"... 有一段时间我无法让它正常工作,那是因为我足够愚蠢地将我的清洁工的可运行清理代码定义为一个匿名类,它保留了(强烈)引用我的指示对象,防止它永远“幻影可达“......

2) There is no other way to implement such efficient cleanup (not even with the help of phantom references) 2)没有其他方法可以实现这种有效的清理(即使借助幻像引用也没有)

Indeed the reference handler thread handles instances of sun.misc.Cleaner in a special way: 实际上,引用处理程序线程以特殊方式处理sun.misc.Cleaner的实例:

// Fast path for cleaners
if (r instanceof Cleaner) {
    ((Cleaner)r).clean();
    continue;
}

That means that the cleanup code is called directly from the reference handler thread, while in standard usage, the references must be enqueued by the reference handler thread and then dequeued and processed by another application thread. 这意味着直接从引用处理程序线程调用清理代码,而在标准用法中,引用必须由引用处理程序线程入队,然后由另一个应用程序线程出列并处理。

If you rely on anything in a sun.misc package, you run the risk of it disappearing and breaking your code. 如果你依赖sun.misc软件包中的任何东西,你就会冒着它消失并破坏代码的风险。 Some pieces are more stable than others, but it's often a bad idea (devil's advocate: a lot of the methods in sun.misc.Unsafe are actually implemented by JVM intrinsics, making them faster than user-written JNI code). 有些部分比其他部分更稳定,但它通常是一个坏主意(魔鬼的拥护者: sun.misc.Unsafe中的很多方法实际上是由JVM内在函数实现的,使得它们比用户编写的JNI代码更快)。

In this case, I think it's a bad idea: Cleaner is one possible implementation of cleanup via PhantomReference . 在这种情况下,我认为这是一个坏主意: Cleaner是通过PhantomReference实现清理的一种可能方式。 There are others; 还有其他人; Google for examples. 以Google为例。 For that matter, you could look at the source code of Cleaner itself as an example of how to use phantom references. 就此而言,您可以查看Cleaner本身的源代码 ,作为如何使用幻像引用的示例。

You will need some sort of cleanup handler if you're going to have on-heap objects that refer to off-heap objects. 如果您要使用引用堆外对象的堆上对象, 需要某种清理处理程序。 Otherwise you'll create a true memory leak when those on-heap objects get collected. 否则,当收集堆栈对象时,您将创建真正的内存泄漏。

Hope it help you if using java9. 希望它对你有帮助,如果使用java9。

The code below was already tested in Intellij IDEA 2017 and oracle jdk 9. 下面的代码已在Intellij IDEA 2017和oracle jdk 9中测试过。

import java.lang.ref.Cleaner;

public class Main {

    public Main() {

    }

    public static void main(String[] args) {
        System.out.println("Hello World!");

        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Cleaner cleaner = Cleaner.create();
            Main obj = new Main();
            cleaner.register(obj, new Runnable() {
                @Override
                public void run() {
                    System.out.println("Hello World!222");
                }
            });
            System.gc();
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 java.lang.ClassNotFoundException:sun.misc.Cleaner - java.lang.ClassNotFoundException: sun.misc.Cleaner 编年史与 corretto jdk17 java.lang.NoSuchMethodError: 'sun.misc.Cleaner sun.nio.ch.DirectBuffer.cleaner()' - chronicle with corretto jdk17 java.lang.NoSuchMethodError: 'sun.misc.Cleaner sun.nio.ch.DirectBuffer.cleaner()' 强制释放本机内存的示例直接ByteBuffer使用sun.misc.Unsafe分配? - Examples of forcing freeing of native memory direct ByteBuffer has allocated, using sun.misc.Unsafe? 渲染问题 java.lang.NoClassDefFoundError: sun/misc/Cleaner - Render issue java.lang.NoClassDefFoundError: sun/misc/Cleaner 使用sun.misc.unsafe获取Java字节数组的内存位置 - getting the memory location for a java byte array using sun.misc.unsafe 使用本机代码中sun.misc.Unsafe.allocateMemory()分配的内存 - Using memory allocated by sun.misc.Unsafe.allocateMemory() in native code 使用sun.misc.Unsafe获取Java数组项的地址? - Using sun.misc.Unsafe to get address of Java array items? 使用sun.misc.Unsafe,从Direct ByteBuffer扫描字节的最快方法是什么? - Using sun.misc.Unsafe, what is the fastest way to scan bytes from a Direct ByteBuffer? 为什么Java 11运行时忽略了包含sun.misc类的jar? - Why is the Java 11 runtime ignoring my jar containing sun.misc classes? 如何在不使用 sun.misc.Unsafe 的情况下触发完整的 memory 围栏? - How to trigger a full memory fence without using sun.misc.Unsafe?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM