자바에서 클래스를 언로드?


174

데스크톱 응용 프로그램이 대화 해야하는 AppServer에서 클래스로드를 동적으로 시작할 수 있도록 사용자 정의 클래스 로더가 있습니다. 우리는이 작업을 수행하는 데 필요한 항아리의 양이 말도 안되기 때문에이 작업을 수행했습니다. 또한 AppServer 라이브러리에서 런타임에 클래스를 동적으로로드하지 않으면 버전 문제가 있습니다.

이제 두 개의 다른 AppServer와 대화 해야하는 문제가 발생하여 처음로드하는 클래스에 따라 나쁘게 중단 될 수 있음을 발견했습니다 ... 실제로 JVM을 종료하지 않고 클래스를 강제로 언로드하는 방법이 있습니까?

이것이 의미가 있기를 바랍니다.


각 병에 대한 클래스 로더가 있습니까? OSGI 컨테이너 아카이브는 어떻게 클래스 로더를 언로드합니까? 클래스 로더 클래스에 언로드 API가없는 것 같습니다.
hetaoblog

답변:


190

클래스를 언로드 할 수있는 유일한 방법은 사용 된 클래스 로더가 가비지 수집 된 경우입니다. 즉, 모든 단일 클래스와 클래스 로더 자체에 대한 참조는 dodo의 길을 가야합니다.

문제에 대한 한 가지 가능한 해결책은 모든 jar 파일에 대해 Classloader를, 클래스의 실제로드를 특정 Jar 클래스 로더에 위임하는 각 AppServer에 대한 Classloader를 갖는 것입니다. 이렇게하면 모든 App 서버에 대해 다른 버전의 jar 파일을 가리킬 수 있습니다.

그러나 이것은 사소한 것이 아닙니다. OSGi 플랫폼은 각 번들에 서로 다른 클래스 로더가 있고 종속성이 플랫폼에 의해 해결되므로이를 수행하려고 노력합니다. 아마도 좋은 해결책은 그것을 살펴 보는 것입니다.

OSGI를 사용하지 않으려는 경우 가능한 모든 구현은 모든 JAR 파일에 대해 하나의 JarClassloader 클래스 인스턴스를 사용하는 것일 수 있습니다 .

그리고 Classloader를 확장하는 새로운 MultiClassloader 클래스를 작성하십시오. 이 클래스는 내부적으로 JarClassloaders의 배열 (또는 List)을 가지며, defineClass () 메소드에서 정의를 찾을 수 있거나 NoClassDefFoundException이 발생 될 때까지 모든 내부 클래스 로더를 반복합니다. 새로운 JarClassloader를 클래스에 추가하기 위해 몇 가지 접근 자 메소드를 제공 할 수 있습니다. 멀티 클래스 로더를위한 네트에는 여러 가지 구현이 가능하므로 직접 작성하지 않아도됩니다.

서버에 대한 모든 연결에 대해 MultiClassloader를 설치하는 경우 원칙적으로 모든 서버가 동일한 클래스의 다른 버전을 사용할 수 있습니다.

사용자 정의 스크립트가 포함 된 클래스를 메모리에서로드 및 언로드 해야하는 프로젝트에서 MultiClassloader 아이디어를 사용했습니다.


31
java.sun.com/docs/books/jls/second_edition/html / ... 에 따르면 클래스 언로드는 최적화이며 JVM 구현에 따라 실제로 발생하거나 발생하지 않을 수 있습니다.

5
OSGi의보다 쉽고 가벼운 대안으로 JBoss Modules-모듈 당 클래스 로더 (jar 그룹)를 사용하여 모듈화 된 클래스 로딩을 시도하십시오 .
Ondra Žižka

42

예. 클래스를로드하고 나중에 "언로드"하는 방법이 있습니다. 트릭은 고급 클래스 로더 (시스템 클래스 로더)와 앱 서버의 클래스 로더 사이에있는 자체 클래스 로더를 구현하고 앱 서버의 클래스 로더가 클래스 로더를 상위 로더에 위임하기를 희망합니다 .

클래스는 패키지, 이름 및 원래로드 된 클래스 로더로 정의됩니다. JVM을 시작할 때 가장 먼저로드되는 "프록시"클래스 로더를 프로그래밍하십시오. 워크 플로우 :

  • 프로그램이 시작되고이 "프록시"클래스가이 프록시 클래스 로더에 의해로드됩니다.
  • 그런 다음 정상적으로로드 된 모든 클래스 (즉, 계층을 손상시킬 수있는 다른 클래스 로더 구현을 통해가 아님)는이 클래스 로더에 위임됩니다.
  • 프록시 클래스 로더 위임 java.xsun.x시스템 클래스 로더에 (이러한 시스템 클래스 로더보다 다른 클래스 로더를 통해로드 할 수).
  • 교체 가능한 모든 클래스에 대해 클래스 로더를 인스턴스화하고 (실제로 클래스를로드하고 상위 클래스 로더에 위임하지 않음)이를 통해로드하십시오.
  • 클래스의 패키지 / 이름을 키로, 클래스 로더를 데이터 구조 (예 : Hashmap)에 값으로 저장하십시오.
  • 프록시 클래스 로더는 이전에로드 된 클래스에 대한 요청을받을 때마다 이전에 저장된 클래스 로더에서 클래스를 리턴합니다.
  • 클래스 로더가 클래스의 바이트 배열을 찾거나 데이터 구조에서 키 / 값 쌍을 "삭제"하여 클래스를 변경하려는 경우 클래스를 다시로드하는 것으로 충분합니다.

ClassCastException 또는 LinkageError 등 이 없어야합니다 .

클래스 로더 계층 구조에 대한 자세한 내용은 (예, 정확히 여기에서 구현하는 것입니다 ;-) Ted Neward의 "Server-Based Java Programming"을 참조하십시오. 이 책은 내가 원하는 것과 매우 유사한 것을 구현하는 데 도움이되었습니다.


3
의견을 남기지 않고이 답변에 -1을 표시 한 사람들을 이해하지 못합니다. 나를 위해 좋아 보인다. 아마도 ClassLoader클래스 당 하나를 갖는 것이 약간 너무 많을 수도 ClassLoader있습니다. 제안 된 스키마에서 클래스 업로드를 강제하는 방법에 대해 더 구체적 일 수 있습니까? 예를 들어 ClassLoaderA에 의해로드 된 클래스의 인스턴스가 ClassLoaderB에 의해로드 된 인스턴스에 의해 참조되지 않는다는 것을 어떻게 보장 할 수 있습니까?
dma_k

@ dma_k 정확하게 대답은 좋지만 언급 한 핵심 사항을 건드리지 않습니다.
zinking

@Georgi 우리가 이것을 위해 재사용 / 재사용 할 수있는 기존 구현이 있습니까?
Sled

1
샘플 자바 코드를 제공 할 수 있다면 매우 도움이 될 것입니다. 정확히 말하면, CustomClassLoader를 사용하여 클래스를 언로드하는 방법을 찾고 있지만 운이 없었습니다.
Sriharsha grv

@ Sriharshag.rv 이것을 시도하고 샘플을 구현 했습니까?
niaomingjian

17

나는 클래스 로더를 GCing하지 않고 개별 클래스를 언로드 할 수있는 사용자 정의 클래스 로더를 작성했습니다. Jar 클래스 로더


매력처럼 작동합니다 :). jar 파일의 모든 클래스 파일을 언로드하는 방법이 있습니까?
Ercksen

불행히도 현재는 아닙니다. 그러나 그것을 들여다 볼 것입니다. 향후 릴리스에있을 수 있습니다.
Kamran

그건 그렇고, 나는 약간의 해결 방법을 찾았습니다. JarClassLoader로드 한 모든 jar 파일에 대해 하나가 있으면이 를 호출 getLoadedClasses()한 다음 각 파일 을 반복하여 언로드하십시오.
Ercksen

12

클래스 로더는 까다로운 문제 일 수 있습니다. 여러 클래스 로더를 사용하고 명확하고 엄격하게 정의 된 상호 작용이없는 경우 특히 문제가 발생할 수 있습니다. 실제로 클래스를 언로드하려면 언로드하려는 클래스 (및 해당 인스턴스)에 대한 모든 참조를 제거해야한다고 생각합니다.

이러한 유형의 작업을 수행해야하는 대부분의 사람들은 OSGi 를 사용 합니다. OSGi는 정말 강력하고 놀랍도록 가벼우 며 사용하기 쉽습니다.


7

ClassLoader를 언로드 할 수 있지만 특정 클래스를 언로드 할 수는 없습니다. 더 구체적으로 제어 할 수없는 ClassLoader에서 작성된 클래스를 언로드 할 수 없습니다.

가능하면 언로드 할 수 있도록 자신 만의 ClassLoader를 사용하는 것이 좋습니다.


4

클래스는 클래스 로더 인스턴스에 대한 암시 적 강력한 참조를 가지며 그 반대도 마찬가지입니다. Java 객체와 같이 가비지 수집됩니다. 도구 인터페이스 등을 치지 않으면 개별 클래스를 제거 할 수 없습니다.

언제나 메모리 누수가 발생할 수 있습니다. 클래스 또는 클래스 로더 중 하나에 대한 강력한 참조는 모든 것을 누출시킵니다. 예를 들어, ThreadLocal, java.sql.DriverManager 및 java.beans의 Sun 구현에서 발생합니다.


-1

언로드 클래스가 JConsole 또는 다른 방식으로 작동하는지 실시간으로보고 있다면 java.lang.System.gc()클래스 언로드 논리의 끝에 추가 하십시오. 가비지 콜렉터를 명시 적으로 트리거합니다.


3
주의 : System.gc ()는 GC를 호출 할 필요가 없습니다. jvm에게만 시작하도록 요청하지만 강제 실행하지는 않습니다. 그리고 IME는 종종 GC를 시작하지 않습니다 :-\
Juh_
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.