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

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

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

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



답변

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

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

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

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

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

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

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


답변

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

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

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

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

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


답변

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


답변

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

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


답변

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

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


답변

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

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


답변

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