
About Unsafe in Java did not hear just lazy, but this is not the only magic class in the Sun / Oracle JDK, erasing the boundaries of the Java platform and opening paths that are not mapped to the public API card. I will talk about some of them that have benefited in real projects. But remember: undocumented features deprive your application of portability to other Java platforms and, in addition, are a potential source of non-trivial errors. I even wrote the word "application" for nothing. It is better to say that the classes described below are not suitable for applications! Rather, they are of interest only for system software and for curious programmers, i.e. for you :)
Cleaner
Every good Java programmer knows that
finalizers are evil . But how can we replace them if there is no guarantee that everyone using our library, like decent programmers, will call close ()? In the end, what is used inside the JDK itself?
In system classes, sun.misc.Cleaner, based on PhantomReference, is used as a more reliable and lightweight replacement for finalizers. As soon as the garbage collector detects that the object referenced by Cleaner has become
phantom-reachable , the specified Runnable will be started, as a rule, to release resources:
public NeedsCleanup() { this.resource = unsafe.allocateMemory(16*1024*1024); Cleaner.create(this, new Destructor(resource)); } private static class Destructor implements Runnable { final long resource; Destructor(long resource) { this.resource = resource; } public void run() { unsafe.freeMemory(resource); } }
Despite its useful sides, this class is not destined to become part of a public API, since, if misused, it can block the Reference Handler stream, or even stop the application.
')
Unmapping MappedByteBuffer
And here is just an example of Cleaner in the JDK system classes.
Whoever used the Java memory-mapped files with FileChannel.map () probably more than once regretted that MappedByteBuffer does not have a unmap () method. There are
reasons for this .
But, as in the saying, if you can not, but really want - you can. The implementation of MappedByteBuffer creates a Cleaner to perform unmap after garbage collection when the buffer becomes unreachable. So, this Cleaner can also be called manually:
public static void unmap(MappedByteBuffer bb) { if (bb instanceof sun.nio.ch.DirectBuffer) { ((sun.nio.ch.DirectBuffer) bb).cleaner().clean(); } }
SharedSecrets
An intriguing name, isn't it? sun.misc.SharedSecrets is a utility class that provides interfaces for accessing certain private data of system classes. Although there are not so many interesting things. You can, say, get to the constant pool of any loaded class ... just do not ask why :)
From what I’ve been able to use, I’m getting a native (OS-level) file descriptor from a Java FileDescriptor object. This is done like this:
public static int getNativeFD(FileDescriptor fd) { return SharedSecrets.getJavaIOFileDescriptorAccess().get(fd); }
Or, for example, how to find out the encoding of the console from which the Java application is running:
if (System.console() != null) { System.out.println(SharedSecrets.getJavaIOAccess().charset()); }
Signalhandler
Did you know that in a Java program you can catch and process POSIX signals, for example, SIGINT?
Yes, using the sun.misc.Signal and sun.misc.SignalHandler classes.
However, I will not dwell on this, since there
has already been an article on this subject.
Magicaccessor
And the most magical class, as the name implies, is today sun.reflect.MagicAccessorImpl. Being inherited from it, your class will miraculously get the opportunity to access all private fields and methods of any classes! The trick is that the bytecode verifier simply omits access checks for the classes that succeed MagicAccessorImpl.
It was very useful to me to implement my own fast serialization mechanism. After all, the serializer should be able to read and write any class fields, including private ones. Traditionally this is achieved by means of Reflection, which is rather slow, or with the help of Unsafe. But there is no way faster than accessing the fields directly via getfield / putfield bytecodes, which are literally compiled into one machine instruction.
Only one problem: only the JVM knows about the magic accessor, but not javac, which will persistently continue to swear for unauthorized access. To test an example, you first have to change the field modifier to public in class A, compile everything, then return the private modifier back and recompile class A separately. Of course, inconvenient, therefore, in practice, inheriting from MagicAccessorImpl makes sense only when dynamically generating a class. By the way, the JDK treasury contains tools for this case: sun.tools.asm.Assembler and the whole package sun.tools.asm.
Warning: Sun proprietary API
As soon as you try to dilute your program with one of the above classes or with any other from the sun package. *, You will certainly receive a warning from the compiler
warning: sun.misc.Unsafe is Sun proprietary API
which cannot be suppressed by any annotations, and rightly so!
You can rejoice or grieve, but in JDK 7, finally, the opportunity to hide the annoying warning. However, again, only with the help of a secret key :)
Add annotation to method or class
@SuppressWarnings("sunapi")
and run javac with parameter
javac -XDenableSunApiLintControl TestUnsafe.java
That's all, the way to experiment is free!