나는 다른 날에 sun.misc.Unsafe 패키지를 발견했고 그것이 할 수있는 것에 놀랐습니다.
물론 수업은 문서화되어 있지 않지만 수업을 사용해야 할 충분한 이유가 있는지 궁금합니다. 어떤 시나리오를 사용해야합니까? 실제 시나리오에서 어떻게 사용될 수 있습니까?
당신이 경우 또한, 할 필요를 뭔가가 아마 당신의 디자인으로 잘못 표시하지 않는 것이, 무엇입니까?
Java에 왜이 클래스가 포함됩니까?
나는 다른 날에 sun.misc.Unsafe 패키지를 발견했고 그것이 할 수있는 것에 놀랐습니다.
물론 수업은 문서화되어 있지 않지만 수업을 사용해야 할 충분한 이유가 있는지 궁금합니다. 어떤 시나리오를 사용해야합니까? 실제 시나리오에서 어떻게 사용될 수 있습니까?
당신이 경우 또한, 할 필요를 뭔가가 아마 당신의 디자인으로 잘못 표시하지 않는 것이, 무엇입니까?
Java에 왜이 클래스가 포함됩니까?
답변:
예
VM "내재화" 즉, 잠금이없는 해시 테이블에 사용 된 CAS (Compare-And-Swap) 예 : sun.misc.Unsafe.compareAndSwapInt CAS에 대한 특별 지침이 포함 된 실제 JNI 호출을 기본 코드로 만들 수 있습니다.
CAS에 대한 자세한 내용은 여기 ( http://en.wikipedia.org/wiki/Compare-and-swap)를 참조하십시오 .
호스트 VM의 sun.misc.Unsafe 기능을 사용하여 초기화되지 않은 객체를 할당 한 다음 생성자 호출을 다른 메소드 호출로 해석 할 수 있습니다.
기본 주소에서 데이터를 추적 할 수 있습니다. java.lang.Unsafe 클래스를 사용하여 객체의 메모리 주소를 검색하고 안전하지 않은 get / put 메소드를 통해 필드에서 직접 조작 할 수 있습니다!
JVM에 대한 컴파일 시간 최적화 "매직"을 사용하는 고성능 VM. 낮은 수준의 작업이 필요합니다. 예 : http://en.wikipedia.org/wiki/Jikes_RVM
메모리 할당 sun.misc.Unsafe.allocateMemory 예 :-ByteBuffer.allocateDirect가 호출 될 때 DirectByteBuffer 생성자가 내부적으로이를 호출합니다.
호출 스택 추적 및 sun.misc로 인스턴스화 된 값으로 재생
sun.misc.Unsafe.arrayBaseOffset 및 arrayIndexScale을 사용하여 대형 객체의 실시간 스캔, 업데이트 또는 이동 작업 비용을 제한하기 위해 대형 어레이를 더 작은 객체로 효율적으로 분할하는 기술인 arraylet을 개발할 수 있습니다.
http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java
여기 참조에 대한 자세한 내용 -http : //bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html
일부 코드 검색 엔진에서 검색 을 실행 하면 다음 예제가 표시됩니다.
{@link Unsafe} 객체에 액세스 할 수있는 간단한 클래스입니다. 어레이에서 효율적인 CAS 작업을 수행하려면 {@link Unsafe} *가 필요합니다. {@link java.util.concurrent.atomic.AtomicLongArray}와 같이 {@link java.util.concurrent.atomic}의 버전에는 일반적으로 이러한 알고리즘에 필요하지 않으며 비용이 많이 드는 추가 메모리 순서 보증이 필요합니다. 대부분의 프로세서에서.
/ ** sun.misc의 기본 클래스 정적 필드의 안전하지 않은 FieldAccessors 리플렉션 코드의 관점에서 볼 때 8 가지 기본 유형과 Object라는 9 가지 유형의 필드 만 관찰됩니다. 생성 된 바이트 코드 대신 Unsafe 클래스를 사용하면 동적으로 생성 된 FieldAccessors의 메모리 및로드 시간이 절약됩니다. * /
/ * 와이어를 통해 전송되는 FinalFields .. 수신 측에서 개체를 비 정렬 화하고 다시 만드는 방법? 최종 필드에 대한 값을 설정하므로 생성자를 호출하고 싶지 않습니다. 발신자 쪽과 마찬가지로 최종 필드를 다시 만들어야합니다. 안전하지 않은 일. * /
다른 많은 예제가 있습니다. 위의 링크를 따르십시오 ...
흥미롭게도, 나는이 수업에 대해 들어 본 적이 없습니다.
한 가지 중요한 점 은 Unsafe # setMemory 를 사용하여 중요한 정보가 포함 된 버퍼 (암호, 키 등)를 0으로 만드는 것입니다. "불변의"객체의 필드에도이 작업을 수행 할 수 있습니다 (그런데 평범한 오래된 리플렉션도 여기서 트릭을 수행 할 수 있습니다). 나는 보안 전문가가 아니므로 소금 한 덩어리로 이것을 가져 가십시오.
I'd never even heard of this class
... 나는 당신에게 그것에 대해 너무 많이 이야기했습니다! 한숨 + :(
park()
문서를 좋아한다 . "현재 스레드 차단, 밸런싱 언 파크가 발생하거나 밸런싱 언 파크가 이미 발생했을 때 리턴, 또는 스레드가 중단되었거나 절대적이지 않고 시간이 0이 아닌 경우 주어진 시간 나노초가 경과했거나, 절대적이라면, Epoch가 경과 한 후 또는 예정대로 (즉, '이유'없이 돌아 오는) 지정된 마감 시간 (밀리 초 ) 입니다. "프로그램이 종료 될 때 메모리가 해제되거나 임의의 간격 중 먼저 오는 것"만큼 좋습니다.
참조 추적에 이클립스를 사용하는 Java 1.6.12 라이브러리에 대한 매우 간단한 분석을 기반으로, 모든 유용한 기능이 Unsafe
유용한 방식으로 노출되는 것처럼 보입니다 .
CAS 작업은 Atomic * 클래스를 통해 노출됩니다. 메모리 조작 기능은 DirectByteBuffer Sync 명령어 (park, unpark)를 통해 노출되며 AbstractQueuedSynchronizer를 통해 노출되며 이는 Lock 구현에서 사용됩니다.
LockSupport
AQS를 통해 노출 되지 않습니다 (후자는 Park / unpark보다 잠금 장치에 더
Unsafe.throwException- 확인 된 예외를 선언하지 않고 던질 수 있습니다.
리플렉션 또는 AOP를 처리하는 경우에 유용합니다.
사용자 정의 인터페이스에 대한 일반 프록시를 작성한다고 가정하십시오. 또한 사용자는 인터페이스에서 예외를 선언하기 만하면 특수한 경우에 함침에 의해 발생하는 예외를 지정할 수 있습니다. 그런 다음 이것이 인터페이스의 동적 구현에서 확인 된 예외를 발생시키는 유일한 방법입니다.
import org.junit.Test;
/** need to allow forbidden references! */ import sun.misc.Unsafe;
/**
* Demonstrate how to throw an undeclared checked exception.
* This is a hack, because it uses the forbidden Class {@link sun.misc.Unsafe}.
*/
public class ExceptionTest {
/**
* A checked exception.
*/
public static class MyException extends Exception {
private static final long serialVersionUID = 5960664994726581924L;
}
/**
* Throw the Exception.
*/
@SuppressWarnings("restriction")
public static void throwUndeclared() {
getUnsafe().throwException(new MyException());
}
/**
* Return an instance of {@link sun.misc.Unsafe}.
* @return THE instance
*/
@SuppressWarnings("restriction")
private static Unsafe getUnsafe() {
try {
Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
singleoneInstanceField.setAccessible(true);
return (Unsafe) singleoneInstanceField.get(null);
} catch (IllegalArgumentException e) {
throw createExceptionForObtainingUnsafe(e);
} catch (SecurityException e) {
throw createExceptionForObtainingUnsafe(e);
} catch (NoSuchFieldException e) {
throw createExceptionForObtainingUnsafe(e);
} catch (IllegalAccessException e) {
throw createExceptionForObtainingUnsafe(e);
}
}
private static RuntimeException createExceptionForObtainingUnsafe(final Throwable cause) {
return new RuntimeException("error while obtaining sun.misc.Unsafe", cause);
}
/**
* scenario: test that an CheckedException {@link MyException} can be thrown
* from an method that not declare it.
*/
@Test(expected = MyException.class)
public void testUnsingUnsaveToThrowCheckedException() {
throwUndeclared();
}
}
Thread.stop(Throwable)
안전하지 않아도 동일한 작업을 수행 할 수 있습니다 . 동일한 스레드에서 어쨌든 무엇이든 던질 수 있습니다 (컴파일 체크 없음)
UnsupportedOperationException
Java 8에서 스텁 아웃되어 현재 스레드에서 throw 됩니다. 그러나 인수가없는 인수 버전은 ThreadDeath
여전히 작동합니다.
안전하지 않은 클래스
안전하지 않은 저수준 작업을 수행하기위한 방법 모음. 클래스와 모든 메소드는 공용이지만이 클래스의 사용은 신뢰할 수있는 코드 만 인스턴스를 얻을 수 있으므로 제한됩니다.
그것을 사용하는 java.util.concurrent.atomic
수업 중 하나입니다 :
효율적인 메모리 복사 (짧은 블록의 경우 System.arraycopy ()보다 복사 속도가 빠름); Java LZF 및 Snappy 코덱에서 사용됩니다 . 바이트 단위로 복사하는 것보다 빠른 'getLong'및 'putLong'을 사용합니다. 16/32/64 바이트 블록과 같은 것을 복사 할 때 특히 효율적입니다.
getLong/putLong
(및 주소도 계산해야 함)
getLong
/ 조합을 사용할 때 x86-64에서 지속적으로 더 나은 성능을 볼 수 있습니다 putLong
. 이상적으로 System.arraycopy()
는 단순함과 모두를 선호 합니다. 그러나 실제 테스트는 내가 테스트 한 경우에 대해 다르게 나타났습니다.
나는 최근에 JVM을 재 구현하는 작업을하고 있었고 놀라운 클래스가로 구현되었다는 것을 발견했다 Unsafe
. 이 클래스는 주로 Java 라이브러리 구현자를 위해 설계되었으며 기본적으로 안전하지는 않지만 빠른 기본 요소를 빌드하는 데 필요한 기능을 포함합니다. 예를 들어, 하드웨어 수준 동기화, 메모리 할당 및 해제 등을 사용하여 원시 필드 오프셋을 가져오고 쓰는 방법이 있습니다. 일반적인 Java 프로그래머가 사용하지는 않습니다. 문서화되지 않고 구현에 따라 다르며 본질적으로 안전하지 않습니다 (따라서 이름!). 또한 SecurityManager
거의 모든 경우에 액세스 할 수 없다고 생각합니다 .
간단히 말해서, 기본적으로 라이브러리 구현자가 기본 클래스와 같은 특정 클래스에서 모든 메소드를 선언하지 않고도 기본 시스템에 액세스 할 수 있도록합니다 AtomicInteger
. 일반적인 Java 프로그래밍에서는이를 사용하거나 걱정할 필요가 없습니다. 요점은 그러한 종류의 액세스가 필요하지 않도록 나머지 라이브러리를 충분히 빠르게 만드는 것입니다.
Unsafe.class.getDeclaredField("theUnsafe")
이 .setAccessible(true)
있으며 그 요구 사항 .get(null)
도 있습니다.
자신의 복셀 엔진과 같이 대량의 메모리에 효율적으로 액세스하고 할당하는 데 사용하십시오! (예 : 마인 크래프트 스타일 게임)
내 경험상 JVM은 종종 필요한 곳에서 경계 검사를 제거 할 수 없습니다. 예를 들어, 큰 배열을 반복하고 있지만 실제 메모리 액세스가 루프의 비가 상 * 메소드 호출 아래에 고정되어있는 경우 JVM이 각 배열 액세스에 대해 한 번이 아니라 한 번만 경계 검사를 수행 할 수 있습니다. 루프. 따라서 잠재적으로 큰 성능 향상을 위해 sun.misc.Unsafe를 사용하여 메모리에 직접 액세스하는 방법을 통해 루프 내에서 JVM 경계 검사를 제거하여 올바른 위치에서 경계 검사를 수행 할 수 있습니다. (당신은 있는 거야 경계를 잘, 어떤 수준에서 확인?)
* 비 가상적으로, 클래스 / 메소드 / 인스턴스가 정적 / 최종 / 무엇의 조합인지 정확하게 보장했기 때문에 JVM이 특정 메소드가 무엇이든 동적으로 해결할 필요가 없음을 의미합니다.
자체 개발 한 복셀 엔진의 경우 청크 생성 및 직렬화 (한 번에 전체 어레이를 읽거나 쓰는 위치) 중에 성능이 크게 향상되었습니다. 결과가 다를 수 있지만 경계 제거 부족이 문제인 경우 문제가 해결됩니다.
이 문제에는 잠재적으로 중대한 문제가 있습니다. 특히 인터페이스의 클라이언트에 대한 경계 검사없이 메모리에 액세스 할 수있는 기능을 제공하면 메모리를 남용 할 수 있습니다. 해커도 인터페이스의 클라이언트가 될 수 있음을 잊지 마십시오. 특히 Java로 작성된 복셀 엔진의 경우에는 메모리 액세스가 남용되지 않도록 인터페이스를 설계해야합니다. 당신은 이제까지 전에 사용자 데이터의 유효성을 검사하기가 매우 조심해야한다 이제까지 당신의 위험한 인터페이스 어울려. 해커가 확인되지 않은 메모리 액세스로 할 수있는 치명적인 일을 고려할 때 두 가지 방법을 모두 사용하는 것이 가장 좋습니다.
직접 사용하지는 않았지만 때로는 두 개 이상의 스레드에서 읽히는 변수가 있으면 (실제로 휘발성으로 만들고 싶지는 않습니다) putObjectVolatile
메인 스레드에서 쓸 때 사용할 수 있고 readObjectVolatile
다른 스레드에서 드문 읽기를 수행 할 때.
사용의 한 예는 random 메소드로, 안전하지 않은 시드 를 호출하여 시드를 변경합니다 .
객체는 Java 코드가 일반적으로 허용하는 것보다 낮은 수준에서 작동 할 수있는 것으로 보입니다. 고급 응용 프로그램을 코딩하는 경우 JVM은 메모리 처리 및 기타 작업을 코드 수준에서 추상화하여 프로그래밍하기 쉽습니다. 안전하지 않은 라이브러리를 사용하면 일반적으로 수행되는 하위 수준 작업을 효과적으로 완료 할 수 있습니다.
woliveirajr가 언급했듯이 "random ()"은 Unsafe를 사용하여 다른 많은 작업이 Unsafe에 포함 된 assignMemory () 함수를 사용하는 것처럼 시드합니다.
프로그래머는 아마도이 라이브러리를 필요로하지 않지만 저수준 요소를 엄격하게 제어 할 수있어 편리 할 것입니다.