Java Instrument (6) 동적 재 정의 Class

이전 블 로그 에서 (http://blog.csdn.net/raintungli/article/details/51646556) 에서 언급 된 재 onattach 방식 에 서 는 class 를 어떻게 다시 정의 하 는 지, 마지막 attach 에 서 는 사용자 정의 에이전트 class 의 agentmain 방법 을 사용 하 는 지, Instrumentation 인터페이스 에 서 는 실제 적 으로 redfineClasses 방법 을 제공 합 니 다.
즉, agentmain 의 방법 은 입 구 를 호출 하 는 것 입 니까? 아니면 sun 자체 가 제공 하 는 Instrumentation 의 redfineClasses 방법 으로 classes 를 교체 해 야 합 니까? 
	public static void agentmain(String agentArgs, Instrumentation inst) {
		ClassDefinition def1 = new ClassDefinition(Class, classByte);
		inst.redefineClasses(new ClassDefinition[]{def1});
	}
sun. intrument. InstrumentationImpl 에서 redefineClasses 는 native redefineClasses 0 을 호출 하 는 방법 입 니 다.
private native void
    redefineClasses0(long nativeAgent, ClassDefinition[]  definitions)
        throws  ClassNotFoundException;
JNIEXPORT void JNICALL Java_sun_instrument_InstrumentationImpl_redefineClasses0
  (JNIEnv * jnienv, jobject implThis, jlong agent, jobjectArray classDefinitions) {
redefineClasses(jnienv, (JPLISAgent*)(intptr_t)agent, classDefinitions);
}
다음은 redefineClasses 의 일부 코드 입 니 다.
void redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitions) {
    if (!errorOccurred) {
        getDefinitionClassMethodID = (*jnienv)->GetMethodID(    jnienv,
                                                classDefClass,
                                                "getDefinitionClass",
                                                "()Ljava/lang/Class;");
     ......
    }
    if (!errorOccurred) {
        getDefinitionClassFileMethodID = (*jnienv)->GetMethodID(    jnienv,
                                                    classDefClass,
                                                    "getDefinitionClassFile",
                                                    "()[B");
        .....
    }
          classDefs[i].klass = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassMethodID);
          ...
          targetFiles[i] = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassFileMethodID);
          ....
           classDefs[i].class_byte_count = (*jnienv)->GetArrayLength(jnienv, targetFiles[i]);
           if (!errorOccurred) {
                    jvmtiError  errorCode = JVMTI_ERROR_NONE;
                    errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs);
		.....
    }
}

전 달 된 ClassDefinition 의 class 대상 과 수정 해 야 할 바이트 코드 를 가 져 와 JVMTI 의 RedefineClasses 방법 을 호출 하 였 습 니 다.
JvmtiEnv::RedefineClasses(jint class_count, const jvmtiClassDefinition* class_definitions) {
//TODO: add locking
  VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine);
  VMThread::execute(&op);
  return (op.check_error());
} /* end RedefineClasses */

그 다음 에 VM Thread 에 맡 겼 습 니 다. 왜 VM Thread 에 맡 겼 습 니까? Class 내용 을 수정 하려 면 Safepoint 에 들 어가 야 하 는 점 은 stop - World 의 작업 이 고 VM Thread 의 작업 은 모두 Safepoint 에 들 어 갑 니 다.
RedefineClasses 는 3 부분 으로 나 뉘 는데 jvmti RedefineClasses. cpp 를 참고 하면 첫 번 째 는 doit 입 니 다.prologue 이 자바 Thread 에서 호출 되 는 것 은 주로 해석 과 검증 으로 전 달 된 by tecode 생 성 scrash 입 니 다.class
  • 대량으로 정의 할 jvmtiClassDefinition
  • 그리고 새로운 바이트 코드 를 읽 습 니 다. ClassFileLoadHook 이벤트 에 관심 이 있 으 면 해당 하 는 transform 으로 새로운 바이트 코드 를 수정 합 니 다
  • 바이트 코드 를 분석 하여 klassoop 대상 을 만 듭 니 다
  •  신 구 류 를 비교 하고 다음 과 같이 요구한다.
  • 부 류 는 동일
  • 실 현 된 인터페이스 수도 같 고 같은 인터페이스
  • 클래스 접근 부호 가 일치 해 야 합 니 다
  • 필드 수 와 필드 이름 이 일치 해 야 합 니 다
  • 새로 추 가 된 방법 은 private static / final
  • 이 어야 합 니 다.
  • 수정 방법 삭제 가능
  • 새로운 종류의 바이트 코드 검사
  • 두 번 째 는 doit () 입 니 다. VMThread 에서 실 행 된 것 은 원래 class 의 내용 을 바 꾸 는 것 입 니 다.
  • 합병 상수
  • 원래 클래스 의 정지점 제거
  • 원래 클래스 의 JIT 최적화 제거
  • 오래된 jmethodId 를 새로운 종류의 jmethodid 에 업데이트
  • 새로운 종류의 상수 탱크 의 hodler 를 오래된 클래스
  • 로 가리킨다.
  • 새로운 유형 과 오래된 유형의 일부 속성 을 교환 합 니 다. 예 를 들 어 상수 탱크, methods, 내부 류
  • 새로운 vtable 과 itable 초기 화
  • annotation 의 method, field, parameter
  • 를 교환 합 니 다.
  • 현재 클래스 의 모든 하위 클래스 를 옮 겨 다 니 며 vtable 및 itable
  • 을 수정 합 니 다.
    세 번 째 는 doitepilogue() 
  • · 주로 앞의 단계 메모리 방출
  • 좋은 웹페이지 즐겨찾기