자바 기반 Unsafe 메모리 작업 불안정 클래스 상세 설명

13086 단어 자바Unsafe종류
간단 한 소개
Unsafe 클래스 는 자바 로 하여 금 C 언어의 포인터 처럼 메모리 공간 을 조작 하 는 능력 을 가지 게 하 였 으 며,직접 메모 리 를 조작 하 는 것 은
1.jvm 의 관 리 를 받 지 않 는 다 는 것 은 GC 에 의 해 수 동 GC 가 필요 하 다 는 것 을 의미 합 니 다.자칫 메모리 누 출 이 발생 할 수 있 습 니 다.
2.Unsafe 의 많은 방법 에서 원본 주소(메모리 주소)와 교 체 된 대상 의 주 소 를 제공 해 야 합 니 다.오프셋 은 스스로 계산 해 야 합 니 다.문제 가 발생 하면 JVM 붕괴 단계 의 이상 으로 인해 전체 JVM 인 스 턴 스 가 무 너 지고 응용 프로그램 이 직접 crash 로 표 시 됩 니 다.
3.메모 리 를 직접 조작 하 는 것 은 속도 가 빠 르 고 동시 다발 적 인 조건 에서 효율 을 잘 향상 시 킬 수 있다 는 것 을 의미한다.
Unsafe 클래스

public final class Unsafe
언 세 이 프 클래스 는'final'로 상속 이 허용 되 지 않 습 니 다.
Unsafe 속성

private static final Unsafe theUnsafe;
public static final int INVALID_FIELD_OFFSET = -1;
public static final int ARRAY_BOOLEAN_BASE_OFFSET;
public static final int ARRAY_BYTE_BASE_OFFSET;
public static final int ARRAY_SHORT_BASE_OFFSET;
public static final int ARRAY_CHAR_BASE_OFFSET;
public static final int ARRAY_INT_BASE_OFFSET;
public static final int ARRAY_LONG_BASE_OFFSET;
public static final int ARRAY_FLOAT_BASE_OFFSET;
public static final int ARRAY_DOUBLE_BASE_OFFSET;
public static final int ARRAY_OBJECT_BASE_OFFSET;
public static final int ARRAY_BOOLEAN_INDEX_SCALE;
public static final int ARRAY_BYTE_INDEX_SCALE;
public static final int ARRAY_SHORT_INDEX_SCALE;
public static final int ARRAY_CHAR_INDEX_SCALE;
public static final int ARRAY_INT_INDEX_SCALE;
public static final int ARRAY_LONG_INDEX_SCALE;
public static final int ARRAY_FLOAT_INDEX_SCALE;
public static final int ARRAY_DOUBLE_INDEX_SCALE;
public static final int ARRAY_OBJECT_INDEX_SCALE;
public static final int ADDRESS_SIZE;
이 속성 들 은 클래스 로 딩 할 때 초기 화 되 며,모두 일부 유형의 배열 지침 입 니 다.
안전 하지 않 은 정적 로드

static {
	registerNatives();
	Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
	theUnsafe = new Unsafe();
	ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
	ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
	ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
	ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
	ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
	ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
	ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
	ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
	ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
	ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
	ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
	ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
	ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
	ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
	ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
	ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
	ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
	ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
	ADDRESS_SIZE = theUnsafe.addressSize();
}
private static native void registerNatives();
Unsafe 구조 함수

private Unsafe() {
}
Unsafe 대상 은 new Unsafe()를 직접 통과 할 수 없습니다.구조 함 수 는 개인 적 입 니 다.
Unsafe 실례 화 방법

public static Unsafe getUnsafe() {
	Class var0 = Reflection.getCallerClass();
	if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
		throw new SecurityException("Unsafe");
	} else {
		return theUnsafe;
	}
}
getUnsafe 는 안내 클래스 로 더(boottstrap class loader)에서 만 불 러 올 수 있 으 며,비 시작 클래스 로 더 는 Unsafe.getUnsafe()방법 을 직접 호출 하면 Security Exception 이상 을 던 집 니 다.해결 방법:
1.코드 를 신뢰 할 수 있 습 니 다.프로그램 을 실행 할 때 JVM 매개 변 수 를 통 해 bootclasspath 옵션 을 설정 하고 시스템 클래스 경로 에 사용 할 Unsafe 경 로 를 지정 합 니 다.

java -Xbootclasspath:/usr/jdk1.7.0/jre/lib/rt.jar:. com.Test
2,자바 반사 메커니즘 을 통 해 폭력 획득.

Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
안전 하지 않 은 메모리 관리

//          (   byte),    4  8。  ADDRESS_SIZE       。
public native int addressSize();
//          ,   2    。
public native int pageSize();
//           ,  bytes        (   byte),           。
public native long allocateMemory(long var1);
//          address            ,           bytes  (   byte)。
public native long reallocateMemory(long var1, long var3);
//                   (   0)
public native void setMemory(Object var1, long var2, long var4, byte var6);
//     
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
//     
public native void freeMemory(long var1);
메모:allocateMemory 방법 으로 신청 한 메모 리 는 jvm 에서 직접 벗 어 날 것 입 니 다.gc 는 이 방식 으로 신청 한 메모 리 를 관리 할 수 없습니다.사용 한 후에 반드시 수 동 으로 메모 리 를 방출 하여 메모리 가 넘 치지 않도록 해 야 합 니 다.
JDK 의 예제:ByteBuffer.allocateDirect(int capacity)는 DirectByteBuffer 를 사용 하고 DirectByteBuffer 에 서 는 allocateMemory 로 외부 메모 리 를 신청 합 니 다.
Unsafe 획득 오프셋

//                 
public native long objectFieldOffset(Field var1);
//              
public native int arrayBaseOffset(Class<?> var1);
//            
public native long staticFieldOffset(Field var1);
//                 ,             
public native int arrayIndexScale(Class<?> var1);
Unsafe 검사 클래스 초기 화

//              。
//  ensureClassInitialized           false
public native boolean shouldBeInitialized(Class<?> c);
//              。
public native void ensureClassInitialized(Class<?> c);
Unsafe 지정 한 위치 에서 읽 기

//               byte
public native byte getByte(long var1);
//               short 
public native short getShort(long var1);
//               char 
public native char getChar(long var1);
//               int 
public native int getInt(long var1);
//               long 
public native long getLong(long var1);
//               float 
public native float getFloat(long var1);
//               double 
public native double getDouble(long var1);
Unsafe 지정 한 위치 에 값 쓰기

//          int 
public native void putInt(long var1, int var3);
//          char 
public native void putChar(long var1, char var3);
//          byte 
public native void putByte(long var1, byte var3);
//          short 
public native void putShort(long var1, short var3);
//          long 
public native void putLong(long var1, long var3);
//          float 
public native void putFloat(long var1, float var3);
//          double 
public native void putDouble(long var1, double var3);
Unsafe 개체 조작
지정 한 오프셋 에서 대상 속성 읽 기(메 인 저장 소 가 아 닌)

public native int getInt(Object var1, long var2);
public native Object getObject(Object var1, long var2);
public native boolean getBoolean(Object var1, long var2);
public native byte getByte(Object var1, long var2);
public native short getShort(Object var1, long var2);
public native char getChar(Object var1, long var2);
public native long getLong(Object var1, long var2);
public native float getFloat(Object var1, long var2);
public native double getDouble(Object var1, long var2);
지정 한 오프셋 에 대상 속성 수정(메 인 저장 소 가 아 닌)

public native void putInt(Object var1, long var2, int var4);
public native void putObject(Object var1, long var2, Object var4);
public native void putBoolean(Object var1, long var2, boolean var4);
public native void putByte(Object var1, long var2, byte var4);
public native void putShort(Object var1, long var2, short var4);
public native void putChar(Object var1, long var2, char var4);
public native void putLong(Object var1, long var2, long var4);
public native void putFloat(Object var1, long var2, float var4);
public native void putDouble(Object var1, long var2, double var4);
지정 한 오프셋 에 대상 속성 수정(메 인 저장)

public native Object getObjectVolatile(Object var1, long var2);
public native int getIntVolatile(Object var1, long var2);
public native boolean getBooleanVolatile(Object var1, long var2);
public native byte getByteVolatile(Object var1, long var2);
public native short getShortVolatile(Object var1, long var2);
public native char getCharVolatile(Object var1, long var2);
public native long getLongVolatile(Object var1, long var2);
public native float getFloatVolatile(Object var1, long var2);
public native double getDoubleVolatile(Object var1, long var2);
지정 한 오프셋 에 대상 속성 수정(메 인 저장)

public native void putObjectVolatile(Object var1, long var2, Object var4);
public native void putIntVolatile(Object var1, long var2, int var4);
public native void putBooleanVolatile(Object var1, long var2, boolean var4);
public native void putByteVolatile(Object var1, long var2, byte var4);
public native void putShortVolatile(Object var1, long var2, short var4);
public native void putCharVolatile(Object var1, long var2, char var4);
public native void putLongVolatile(Object var1, long var2, long var4);
public native void putFloatVolatile(Object var1, long var2, float var4);
public native void putDoubleVolatile(Object var1, long var2, double var4);
public native void putOrderedObject(Object var1, long var2, Object var4);
public native void putOrderedObject(Object var1, long var2, Object var4);
public native void putOrderedInt(Object var1, long var2, int var4);
public native void putOrderedLong(Object var1, long var2, long var4);
안전 하지 않 은 CAS 조작

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
대상 을 대상 으로 CAS 작업 을 진행 합 니 다.본질 업데이트 대상 에서 오프셋 의 속성 을 지정 합 니 다.원래 값 이 var 4 일 때 만 var 5 로 업데이트 되 고 true 로 돌아 갑 니 다.그렇지 않 으 면 false 로 돌아 갑 니 다.
예:volatile i=0;여러 개의 스 레 드 가 i 의 값 을 수정 합 니 다.A 스 레 드 는 i=1 시 에 만 2 로 수정 합 니 다.코드 가 다음 과 같 으 면.

if (i == 1) {i = 2;} 
이 럴 때 문제 가 있 습 니 다.if 비교 완료 i 는 다른 사람 에 의 해 수정 되 었 을 수 있 습 니 다.이런 장면 은 CAS 에 특히 적합 합 니 다.CAS 코드 를 사용 하면 다음 과 같 습 니 다.

boolean isUpdate =  compareAndSwapInt(object, offset, 1, 2)
읽 기->판단->한 번 써 서 해결 하 는 것 과 같다.
Unsafe 스 레 드 의 연결 및 복구

public native void park(boolean var1, long var2);
unpark 방법 이 나타 날 때 까지 현재 스 레 드 를 막 습 니 다.time 이 0 이 아 닌 상황 에서 isAbsolute 가 true 라면 time 은 신기원 이후 의 밀리초 에 비해 그렇지 않 으 면 time 은 나 초 를 나타 낸다.이 방법 은 실 행 될 때 도 불합리 하 게 되 돌아 갈 수 있다.또한 자바 util.concurrent 의 프레임 워 크 가 스 레 드 에 대한 연결 작업 은 LockSupport 류 에 봉인 되 어 있 으 며,LockSupport 류 에는 다양한 버 전 pack 방법 이 있 으 나,최종 적 으로 Unsafe\#park()방법 이 호출 되 었 습 니 다.

public native void unpark(Object var1);
파 크 가 만 든 스 레 드 에 있 는 차단 을 해제 합 니 다.이 방법 은 이전에 파 크 를 호출 하여 발생 한 차단 을 중지 하 는 데 도 사용 할 수 있다.이 조작 은 안전 하지 않 기 때문에 스 레 드 가 생존 하도록 확보 해 야 합 니 다(thread has not been destroyed).자바 코드 에서 하나의 스 레 드 가 살아 있 는 지 여 부 를 판단 하 는 것 은 분명 하지만,native 코드 에서 이 기 회 는 자동 으로 완성 할 수 없습니다.
안전 하지 않 은 메모리 장벽

public native void loadFence();
이 방법 이전의 모든 읽 기 동작 은 반드시 load 장벽 전에 실 행 됩 니 다.

public native void storeFence();
이 방법 전의 모든 쓰기 동작 은 store 장벽 전에 실 행 됩 니 다.

public native void fullFence();
이 방법 이전의 모든 읽 기와 쓰기 작업 은 반드시 full 장벽 전에 실 행 됩 니 다.이 메모리 장벽 은 위의 두 개의(load 장벽 과 store 장벽)의 합 체 기능 에 해당 합 니 다.
안전 하지 않 은 기타

public native int getLoadAverage(double[] loadavg, int nelems);
시스템 의 평균 부하 값 을 가 져 옵 니 다.loadavg 라 는 double 배열 은 부하 값 의 결 과 를 저장 합 니 다.nelems 는 샘플 의 수량 을 결정 합 니 다.nelems 는 1 에서 3 까지 만 가 져 올 수 있 습 니 다.각각 최근 1,5,15 분 동안 시스템 의 평균 부하 입 니 다.시스템 의 부 하 를 가 져 올 수 없다 면,이 방법 은-1 을 되 돌려 줍 니 다.그렇지 않 으 면 가 져 온 견본 의 수량(loadavg 에서 유효한 요소 개수)을 되 돌려 줍 니 다.실험 에서 이 방법 은 계속-1 로 되 돌아 가 는데 사실은 JMX 의 관련 방법 으로 이 방법 을 대체 할 수 있다.

public native void throwException(Throwable ee);
검 측 메커니즘 을 돌아 서 직접 이상 을 던지다.
자바 기반 의 Unsafe 메모리 조작 불안 전 류 에 대한 자세 한 설명 은 여기까지 입 니 다.더 많은 Unsafe 메모리 조작 불안 전 류 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 지원 바 랍 니 다!

좋은 웹페이지 즐겨찾기