Java UnSafe 클래스 사용 안내
Unsafe
는 자바 전체 와 하 도 급 베이스 실현 의 핵심 으로 C++의 포인터 처럼 메모 리 를 직접 조작 하 는 능력 을 가지 고 있 으 며 이것 은 JVM 의 제한 을 넘 었 다 는 것 을 의미한다.Unsafe
의 특성 은 다음 과 같이 요약 할 수 있다.이 는 어느 정도 효율 을 높 였 지만 지침 의 불안정 성 을 가 져 왔 다.Unsafe
JVM 관 리 를 받 지 않 으 면 자동 GC 가 되 지 않 고 수 동 GC 가 필요 해 메모리 누 출Unsafe
의 대부분 방법 은 원본 주소(메모리 주소)와 교 체 된 대상 의 주 소 를 제공 해 야 하 며,편 이 량 은 스스로 계산 해 야 하 며,문제 가 발생 하면 JVM 붕괴 단계 의 이상 이 발생 하여 전체 응용 프로그램 이 직접 crash2.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()
방법 으로 사용 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.