Unsafe 클래스 getBoolean 방법 분석
4351 단어 openjdk
public native boolean getBoolean(Object var1, long var2);
자바 로 컬 방법 은 jni 호출 로 이 루어 집 니 다.
jboolean, Unsafe_GetBoolean(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)
실제
jboolean, Unsafe_Get##Boolean(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)
매크로 에 정의 되 어 있 습 니 다.\# 연결 연산 자 를 사 용 했 습 니 다. 내용 은?
UNSAFE_ENTRY(jboolean, Unsafe_Get##Boolean(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) \
UnsafeWrapper("Unsafe_Get"#Boolean); \
GET_FIELD(obj, offset, jboolean, v); \
return v; \
UNSAFE_END \
원칙 은 호출 이다
GET_FIELD(obj, offset, jboolean, v)
원본 코드 보기
#define GET_FIELD(obj, offset, type_name, v) \
oop p = JNIHandles::resolve(obj); \
type_name v = *(type_name*)index_oop_from_field_offset_long(p, offset)
다시 보 자 indexoop_from_field_offset_long 방법
inline void* index_oop_from_field_offset_long(oop p, jlong field_offset) {
jlong byte_offset = field_offset_to_byte_offset(field_offset);
#ifdef ASSERT
if (p != NULL) {
assert(byte_offset >= 0 && byte_offset <= (jlong)MAX_OBJECT_SIZE, "sane offset");
if (byte_offset == (jint)byte_offset) {
void* ptr_plus_disp = (address)p + byte_offset;
assert((void*)p->obj_field_addr((jint)byte_offset) == ptr_plus_disp,
"raw [ptr+disp] must be consistent with oop::field_base");
}
jlong p_size = HeapWordSize * (jlong)(p->size());
assert(byte_offset < p_size, err_msg("Unsafe access: offset " INT64_FORMAT " > object's size " INT64_FORMAT, byte_offset, p_size));
}
#endif
if (sizeof(char*) == sizeof(jint)) // (this constant folds!)
return (address)p + (jint) byte_offset;
else
return (address)p + byte_offset;
}
들 어 오 는 대상 의 주 소 를 알려 주 고 되 돌아 오 는 형식의 오프셋 을 알려 주 는 것 입 니 다. 그리고 c++ 포인터 와 오프셋 을 통 해 해당 하 는 주소 의 초기 위 치 를 되 돌려 주 고 유형 (포인터 유형 확인) 에 따라 대응 하 는 형식의 값 으로 되 돌려 줍 니 다. 주소 + 오프셋 = 대응 하 는 데이터 의 주소 입 니 다.
자바 가 들 어 오 는 fieldOffset 이 어떤 값 인지 확인 해 보 겠 습 니 다.
package com.jinrong.zaxiang.refect;
import java.lang.reflect.Field;
/**
* @author wocan23
* @create 2019/9/24 5:56
*/
public class RefectTest {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
User user = new User();
user.setAge(2);
user.setName("zss");
user.setFlagStudent(true);
Class aClass = user.getClass();
Field flagStudentField = aClass.getDeclaredField("flagStudent");
flagStudentField.setAccessible(true);
boolean aBoolean = flagStudentField.getBoolean(user);
Field nameField = aClass.getDeclaredField("name");
nameField.setAccessible(true);
Object o = nameField.get(user);
Field ageField = aClass.getDeclaredField("age");
ageField.setAccessible(true);
Object o1 = ageField.getInt(user);
}
}
class User{
private int age; // offset 12
private String name; // offset 20
private boolean flagStudent; // offset 16
public boolean isFlagStudent() {
return flagStudent;
}
public void setFlagStudent(boolean flagStudent) {
this.flagStudent = flagStudent;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
정지점 에서 offset 이 16 인 것 을 발 견 했 습 니 다. name 과 age 의 offset 이 얼마나 되 는 지 20 과 12 로 순 서 를 바 꾸 었 습 니 다. 오프셋 은 변 하지 않 았 습 니 다.
변 수 를 하나 더 추가 합 니 다.
class User{
private String name; // offset 20
private int age; // offset 12
private boolean flagStudent; // offset 16
private boolean flagMale; // offset 17
새로 추 가 된 것 만 바 뀌 었 을 뿐 실제 바이트 코드 의 순서 와 성명 순서 가 다르다 는 것 을 발견 했다.
또 멤버 들 은 12 부터 64 비트 자바 가상 머 신 에 압축 포인터 개념 (대응 가상 머 신 옵션 - XX: + UseCompressedOops, 기본 오픈) 을 도입 해 64 비트 의 자바 대상 지침 을 32 비트 로 압축 했다.이렇게 되면 대상 헤드 의 유형 포인터 도 32 비트 로 압축 되 어 대상 헤드 크기 를 16 바이트 에서 12 바이트 로 낮 출 수 있다.