Java UnSafe 클래스 사용 안내

25918 단어 Java기초
글 목록
  • 1.UnSafe 프로필
  • 2.UnSafe 기능 과 사용 예시
  • 2.1 조작 대상 속성
  • 2.2 배열 요소 조작
  • 2.3 메모리 주소 조작
  • 2.4 CAS 조작
  • 2.5 스 레 드 연결 및 복구
  • 2.6 메모리 장벽
  • 2.7 Class 관련
  • 1.UnSafe 소개Unsafe는 자바 전체 와 하 도 급 베이스 실현 의 핵심 으로 C++의 포인터 처럼 메모 리 를 직접 조작 하 는 능력 을 가지 고 있 으 며 이것 은 JVM 의 제한 을 넘 었 다 는 것 을 의미한다.Unsafe의 특성 은 다음 과 같이 요약 할 수 있다.이 는 어느 정도 효율 을 높 였 지만 지침 의 불안정 성 을 가 져 왔 다.
  • UnsafeJVM 관 리 를 받 지 않 으 면 자동 GC 가 되 지 않 고 수 동 GC 가 필요 해 메모리 누 출
  • 이 발생 하기 쉽다.
  • Unsafe의 대부분 방법 은 원본 주소(메모리 주소)와 교 체 된 대상 의 주 소 를 제공 해 야 하 며,편 이 량 은 스스로 계산 해 야 하 며,문제 가 발생 하면 JVM 붕괴 단계 의 이상 이 발생 하여 전체 응용 프로그램 이 직접 crash
  • 를 초래 할 수 있다.
  • 메모 리 를 직접 조작 하 는 것 은 속도 가 빠 르 고 동시 다발 적 인 조건 에서 효율 을 잘 향상 시 킬 수 있다 는 것 을 의미한다
  • .
    2.UnSafe 기능 및 사용 예시Unsafe류 의 구조 함 수 는 개인 적 인 것 이 고 대외 적 으로 제공 하 는 정적 방법Unsafe#getUnsafe()은 호출 자의ClassLoader에 제한 이 있 습 니 다.만약 에 이 방법의 호출 자가 Boot ClassLoader 에 의 해 로드 되 지 않 으 면 잘못 보고 할 수 있 습 니 다.
    public static Unsafe getUnsafe() {
            Class var0 = Reflection.getCallerClass();
            if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
                throw new SecurityException("Unsafe");
            } else {
                return theUnsafe;
            }
        }
    

    자바 소스 코드 에서 개발 자가 사용자 정의 하 는 클래스 는 모두Appliaction ClassLoader로 불 러 오기 때문에 정상 적 인 상황 에서 우 리 는 직접 사용 할 수 없습니다Unsafe.이 를 사용 하려 면 반 사 를 이용 해 야 합 니 다.
    public static Unsafe getUnsafe() {
            Unsafe unsafe = null;
            try {
                Field field = Unsafe.class.getDeclaredField("theUnsafe");
                field.setAccessible(true);
                unsafe = (Unsafe) field.get(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return unsafe;
        }
    

    2.1 조작 대상 속성
    방법.
    기능.public native Object getObject(Object o, long offset)
    자바 대상 에서 오프셋 주 소 를 offset 속성 으로 하 는 값 을 가 져 옵 니 다.이 방법 은 수정자 의 제한 을 돌파 할 수 있 습 니 다.유사 한 방법 은getInt()、getDouble()등 이 있 습 니 다.마찬가지 로 putObject()방법 도 있 습 니 다.public native Object getObjectVolatile(Object o, long offset)
    메 인 메모리 에서 대상 이 지정 한 오프셋 의 속성 치 를 강제로 가 져 옵 니 다.유사 한 방법 은getIntVolatile()、getDoubleVolatile()등 이 있 습 니 다.마찬가지 로putObjectVolatile()도 있 습 니 다.public native void putOrderedObject(Object o, long offset, Object x)
    대상 의 오프셋 주소 offset 에 대응 하 는 대상 유형 속성의 값 을 지정 값 으로 설정 합 니 다.이것 은 질서 가 있 거나 지연 되 는putObjectVolatile()방법 이 며,값 의 변 화 를 다른 스 레 드 에 의 해 즉시 볼 수 없다.속성 이volatile수식 되 고 수정 되 기 를 기대 할 때 만 사용 할 수 있 습 니 다.유사 한 방법 은putOrderedInt() putOrderedLong()public native long objectFieldOffset(Field f)
    주어진 비정 상 속성 이 클래스 의 저장 소 분배 에 있 는 위치(오프셋 주소)를 되 돌려 주 고 오프셋 주소 에 따라 속성 을 직접 수정 할 수 있 으 며 속성 에 대한 접근 수정자 제한 을 돌파 할 수 있 습 니 다.
    
    private String name;
    
    @Test
    public void test() {
            Unsafe unsafe = getUnsafe();
            try {
                DirectMemory directMemory = (DirectMemory) unsafe.allocateInstance(DirectMemory.class);
                long nameOffset = unsafe.objectFieldOffset(DirectMemory.class.getDeclaredField("name"));
                unsafe.putObject(directMemory, nameOffset, "luck");
                System.out.println(directMemory.getName());
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
    

    2.2 조작 배열 요소
    방법.
    기능.public native int arrayBaseOffset(Class arrayClass)
    배열 형식의 첫 번 째 요소 의 오프셋 주소(기본 오프셋 주소)를 되 돌려 줍 니 다.public native int arrayIndexScale(Class arrayClass)
    배열 의 요소 와 요소 간 의 오프셋 주소 의 증 가 를 되 돌려 줍 니 다.arrayBaseOffset()와 함께 사용 하면 모든 요소 의 주 소 를 찾 을 수 있 습 니 다.
    
    private String[] names = {"nathan", "goog", "luck"};
      
    @Test
    public void test() {
            Unsafe unsafe = getUnsafe();
            try {
                 Class<?> a = String[].class;
                 int base = unsafe.arrayBaseOffset(a);
                 int scale = unsafe.arrayIndexScale(a);
                 // base + i * scale           i             
                 System.out.println(unsafe.getObject(names, (long) base + 2 * scale));
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
    
    ForkJoinPool에서 새로운 요소 포 지 셔 닝 알고리즘 이 있 는데 이런 방법 은 요소 의 메모리 크기 가 2 인 차 멱 을 요구한다scale.만약scale이 4 와 같다 면 ASHIFT 값 은 2 이 고 4 곱 하기 와 왼쪽으로 2 자리 이동 결 과 는 같 지만 이동 조작 은 더욱 효율 적 이다.
    ASHIFT = 31 - Integer.numberOfLeadingZeros(scale)
    offset = (i << ASHIFT) + ABASE
    

    2.3 메모리 주소 조작
    방법.
    기능.public native int addressSize()
    로 컬 포인터 의 크기(단 위 는 byte)를 가 져 옵 니 다.보통 값 은 4 또는 8 입 니 다.public native int pageSize()
    로 컬 메모리 의 페이지 수 를 가 져 옵 니 다.이 값 은 2 의 제곱 입 니 다.public native long allocateMemory(long bytes)
    새 로 컬 메모 리 를 할당 합 니 다.bytes 를 통 해 메모리 블록 의 크기(단 위 는 byte)를 지정 하고 새로 열 린 메모리 의 주 소 를 되 돌려 줍 니 다.public native long reallocateMemory(long address, long bytes)
    지정 한 메모리 주소 address 를 통 해 로 컬 메모리 블록 크기 를 재 조정 합 니 다.조 정 된 메모리 블록 크기 는 bytes 를 통 해 지정 합 니 다(단 위 는 byte)public native void setMemory(Object o, long offset, long bytes, byte value)
    주어진 메모리 블록 에 있 는 모든 바이트 를 고정 값 으로 설정 합 니 다(보통 0)
    public class DirectMemoryBuffer {
        private final static int BYTE = 1;
        private long size;
        private long address;
        private Unsafe unsafe;
    
        public DirectMemoryBuffer(long size, Unsafe unsafe) {
            this.size = size;
            this.unsafe = unsafe;
            address = unsafe.allocateMemory(size * BYTE);
        }
    
        public void set(long i, byte value) {
            unsafe.putByte(address + i * BYTE, value);
        }
    
        public int get(long idx) {
            return unsafe.getByte(address + idx * BYTE);
        }
    
        public long size() {
            return size;
        }
    
        public void freeMemory() {
            unsafe.freeMemory(address);
        }
    }
    

    2.4 CAS 조작
    CAS 는 낙관적 인 자물쇠 체제 로 자 물 쇠 를 선점 할 필요 가 없고 효율 을 효과적으로 향상 시 키 며 하드웨어 에 의존 하 는 원자 조작 실현 이다.
    방법.
    기능.public final native boolean compareAndSwapObject(Object target, long offset, Object exceptData, Object targetData)
    그 역할 은 목표 대상 이 지정 한 오프셋 속성 을 비교 하 는 기대 치 와 메 인 메모리 의 값 이 같 으 면 메 인 메모리 의 값 을 목표 값 으로 업데이트 합 니 다.마찬가지 로compareAndSwapInt() compareAndSwapLong()
    public class CASCounter {
        private Unsafe unsafe;
        // count       volatile           
        private volatile long count = 0;
        private long offset;
    
        public CASCounter(Unsafe unsafe) {
            this.unsafe = unsafe;
            try {
                offset = unsafe.objectFieldOffset(CASCounter.class.getDeclaredField("count"));
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    
        //     increment   ,   while           compareAndSwapLong,       count   
        //               。   ,     ,     ,          
        public void increment() {
            long before = count;
            while (!unsafe.compareAndSwapLong(this, offset, before, before + 1)) {
                before = count;
            }
        }
    
        public long getCount() {
            return count;
        }
    }
    

    2.5 스 레 드 연결 및 복구
    방법.
    기능.public native void park(boolean isAbsolute, long time)
    현재 스 레 드 를 막 고unpark()방법 이 호출 되 거나 시간 을 초과 할 때 까지 기 다 립 니 다.Object.await()와 매우 유사 하지만 파 크 는 운영 체제 가 호출 되 기 때문에 일부 운영 체제 구조 에서 더욱 좋 은 성능 을 가 져 올 수 있 습 니 다.public native void unpark(Object thread)
    파 크 에 의 해 막 힌 스 레 드 를 깨 우 는 것 은 안전성 이 없 기 때문에 스 레 드 가 생존 하도록 해 야 합 니 다.
    2.6 메모리 장벽
    방법.
    기능.public native void loadFence()
    메모리 장벽 을 늘 리 지 않 으 면 수 동 으로 장벽 을 늘 릴 수 있다.이 방법 이전의 모든 읽 기 동작 은 반드시 load 장벽 전에 실 행 됩 니 다.public native void storeFence()
    이 방법 전의 모든 쓰기 동작 은 store 장벽 전에 실 행 됩 니 다.public native void fullFence()
    이 방법 이전의 모든 읽 기와 쓰기 작업 은 반드시 full 장벽 전에 실 행 됩 니 다.이 메모리 장벽 은 위의 두 개의(load 장벽 과 store 장벽)의 합 체 기능 에 해당 합 니 다.
    2.7 클래스 관련
    방법.
    기능.public native boolean shouldBeInitialized(Class> c)
    클래스 를 초기 화 할 지 여 부 를 판단 합 니 다.보통 클래스 의 정적 속성 을 가 져 올 때 사용 합 니 다.(클래스 가 초기 화 되 지 않 으 면 정적 속성 도 초기 화 되 지 않 습 니 다.)ensureClassInitialized 방법 이 적용 되 지 않 을 때 만 false 로 돌아 갑 니 다.public native void ensureClassInitialized(Class> c)
    주어진 클래스 가 초기 화 되 었 는 지 확인 합 니 다.보통 클래스 의 정적 속성 을 가 져 올 때 사용 합 니 다.(클래스 가 초기 화 되 지 않 으 면 정적 속성 도 초기 화 되 지 않 기 때 문 입 니 다)public native Class> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain)
    클래스 를 정의 합 니 다.이 방법 은 JVM 의 모든 보안 검 사 를 건 너 뜁 니 다.기본 적 인 상황 에서 ClassLoader(클래스 로 더)와 Protection Domain(보호 도 메 인)인 스 턴 스 는 호출 자 에서 유래 합 니 다.public native Class> defineAnonymousClass(Class> hostClass, byte[] data, Object[] cpPatches)
    익명 클래스 정의public native long staticFieldOffset(Field f)
    주어진 정적 속성 이 클래스 의 저장 소 할당 에 있 는 위치(위치 이동)를 되 돌려 줍 니 다.public native Object staticFieldBase(Field f)
    주어진 정적 속성의 위 치 를 되 돌려 주 고 배합staticFieldOffset()방법 으로 사용 합 니 다.

    좋은 웹페이지 즐겨찾기