Java Language
sun.misc.Unsafe
수색…
비고
Unsafe
클래스는 프로그램이 Java 컴파일러에서 허용하지 않는 작업을 수행 할 수있게합니다. 일반 프로그램은 Unsafe
사용을 피해야합니다.
경고
Unsafe
API를 사용하여 실수를하면 응용 프로그램에서 JVM이 충돌하거나 진단하기 어려운 증상을 나타낼 수 있습니다.Unsafe
API는 사전 통보없이 변경 될 수 있습니다. 코드에서 사용하는 경우 Java 버전을 변경할 때 코드를 다시 작성해야 할 수 있습니다.
리플렉션을 통해 sun.misc.Unsafe 인스턴스화
public static Unsafe getUnsafe() {
try {
Field unsafe = Unsafe.class.getDeclaredField("theUnsafe");
unsafe.setAccessible(true);
return (Unsafe) unsafe.get(null);
} catch (IllegalAccessException e) {
// Handle
} catch (IllegalArgumentException e) {
// Handle
} catch (NoSuchFieldException e) {
// Handle
} catch (SecurityException e) {
// Handle
}
}
sun.misc.Unsafe
에는 Private 생성자가 있으며 정적 getUnsafe()
메서드는 클래스 로더를 검사하여 코드가 기본 클래스 로더와 함께로드되었는지 확인합니다. 따라서 인스턴스를로드하는 한 가지 방법은 리플렉션을 사용하여 정적 필드를 가져 오는 것입니다.
bootclasspath를 통해 sun.misc.Unsafe 인스턴스화하기
public class UnsafeLoader {
public static Unsafe loadUnsafe() {
return Unsafe.getUnsafe();
}
}
이 예제가 컴파일되지만 Unsafe 클래스가 기본 클래스 로더와 함께로드되지 않으면 런타임에 실패 할 가능성이 있습니다. JVM은 다음과 같은 적절한 인수로로드되어야합니다.
java -Xbootclasspath:$JAVA_HOME/jre/lib/rt.jar:./UnsafeLoader.jar foo.bar.MyApp
foo.bar.MyApp
클래스는 UnsafeLoader.loadUnsafe()
를 사용할 수 있습니다.
안전하지 않은 인스턴스 가져 오기
안전하지 않은 항목은 직접 액세스 할 수없는 비공개 필드로 저장됩니다. 생성자는 private이며 public static Unsafe getUnsafe()
에 액세스하는 유일한 방법은 권한있는 액세스 권한 public static Unsafe getUnsafe()
집니다. 리플렉션을 사용하여 비공개 필드에 액세스 할 수있게하는 해결 방법이 있습니다.
public static final Unsafe UNSAFE;
static {
Unsafe unsafe = null;
try {
final PrivilegedExceptionAction<Unsafe> action = () -> {
final Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe) f.get(null);
};
unsafe = AccessController.doPrivileged(action);
} catch (final Throwable t) {
throw new RuntimeException("Exception accessing Unsafe", t);
}
UNSAFE = unsafe;
}
안전하지 않은 사용
안전하지 않은 용도는 다음과 같습니다.
용도 | API |
---|---|
힙 / 직접 메모리 할당 해제, 재 할당 및 할당 취소 | allocateMemory(bytes) , reallocateMemory(address, bytes) 및 freeMemory(address) |
메모리 울타리 | loadFence() , storeFence() , fullFence() |
주차 현재 스레드 | park(isAbsolute, time) , unpark(thread) |
직접 필드 및 / 또는 메모리 액세스 | 메소드의 get* 및 put* 패밀리 |
확인되지 않은 예외를 던집니다. | throwException(e) |
CAS 및 원자 적 조작 | compareAndSwap* 메소드의 패밀리 |
메모리 설정하기 | setMemory |
휘발성 또는 동시 작업 | get*Volatile , put*Volatile , putOrdered* |
get 및 put 메소드 군은 주어진 객체에 상대적입니다. 오브젝트가 null의 경우, 절대 주소로서 다루어집니다.
// Putting a value to a field
protected static long fieldOffset = UNSAFE.objectFieldOffset(getClass().getField("theField"));
UNSAFE.putLong(this, fieldOffset , newValue);
// Puting an absolute value
UNSAFE.putLong(null, address, newValue);
UNSAFE.putLong(address, newValue);
일부 메소드는 int 및 long에 대해서만 정의됩니다. floatToRawIntBits
, intBitsToFloat,
doubleToRawLongBits ,
longBitsToDouble`을 사용하여 float 및 double에서이 메서드를 사용할 수 있습니다.