Java 응용 프로그램에서로드 된 클래스 수의 메모리 누출 가능

StackOverflow https://stackoverflow.com/questions/167740

  •  03-07-2019
  •  | 
  •  

문제

나는 최근에 VisualVM을 사용하여 작성하는 OSGI Java 응용 프로그램을 프로파일 링하기 시작했습니다. 내가 알아 차린 한 가지는 응용 프로그램이 클라이언트 (JMS 이상)에 데이터를 보내기 시작하면로드 된 클래스의 수가 꾸준히 증가하기 시작한다는 것입니다. 그러나 힙 크기와 Permgen 크기는 일정하게 유지됩니다. 데이터 전송을 중단 한 후에도 클래스 수는 절대 떨어지지 않습니다. 이것은 메모리 누출입니까? 로드 된 클래스는 어딘가에 저장되어야하기 때문에 힙과 영구는 몇 시간 동안 응용 프로그램을 실행 한 후에도 결코 증가하지 않습니다.

프로파일 링 애플리케이션의 스크린 샷은 이동합니다 여기

도움이 되었습니까?

해결책

어떻게 든 즉시 새로운 수업을 만들고 있습니까?

당신의 도움을 주셔서 감사합니다. 나는 문제가 무엇인지 알아 냈다. 수업 중 하나에서 jaxb를 사용하여 XML 문자열을 만들었습니다. 이를 수행 할 때 Jaxb는 새로운 클래스를 만들기 위해 반사를 반사합니다.

JAXBContext context = JAXBContext.newInstance(this.getClass());

따라서 jaxbcontext는 힙에서 말하지 않았지만 클래스가로드되었습니다.

나는 다시 프로그램을 실행했고, 내가 기대할 수있는 정상적인 고원을 본다.

다른 팁

나는 당신의 문제가 바이트 코드 생성과 관련이 있다고 기꺼이 내기를 기꺼이 할 것입니다.

많은 라이브러리는 cglib, bcel, javasist 또는 janino를 사용하여 런타임에서 새로운 클래스에 대한 바이트 코드를 생성 한 다음 제어 된 클래스 로더에서로드합니다. 이 클래스를 릴리스하는 유일한 방법은 클래스 로더에 대한 모든 참조를 출시하는 것입니다.

클래스 로더는 각 클래스에서 보유되므로 모든 클래스에 대한 참조를 해제해서는 안된다는 것을 의미합니다 [1]. 괜찮은 프로파일 러로 이들을 잡을 수 있습니다 (나는 YourKit을 사용합니다 - 동일한 유지 크기의 동일한 클래스 로더 인스턴스를 검색합니다).

한 가지 캐치는 JVM이 기본적으로 클래스를 내리지 않는 것입니다 (이유는 뒤로 호환성이 있습니다. 사람들은 정적 초기화기가 한 번만 실행될 것이라고 (잘못) 가정합니다. 진실은 클래스가로드 될 때마다 실행된다는 것입니다.) 언로드 활성화를 활성화하면 다음 옵션을 사용해야합니다.

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled

(JDK 1.5로 테스트)

그럼에도 불구하고 과도한 바이트 코드 생성은 좋은 생각이 아니므로 원인을 찾아 범인을 찾아 생성 된 클래스를 캐시하기 위해 코드를 살펴 보는 것이 좋습니다. 빈번한 범죄자는 스크립팅 언어, 동적 프록시 (응용 프로그램 서버에 의해 생성 된 프록시 포함) 또는 거대한 최대 절전 모드 (이 경우 Permgen을 증가시킬 수 있음)입니다.

또한보십시오:

  1. http://blogs.oracle.com/watt/resource/jvm-options-list.html
  2. http://blogs.oracle.com/jonthecollector/entry/presenting_the_permanent_generation
  3. http://forums.sun.com/thread.jspa?messageid=2833028

이 동작을 다음과 같이 이해하는 데 사용할 핫스팟 플래그를 찾을 수 있습니다.

  • -xx :+traceclassloading
  • -xx :+traceclassunloading

이것은 좋은 참조입니다.

http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

내가 오해하지 않는 한, 우리는 인스턴스가 아닌로드 클래스를 여기에서보고 있습니다.

코드가 클래스를 처음 참조하면 JVM에는 클래스 로더가 꺼내어 .class 파일 등의 클래스에 대한 정보를 가져옵니다.

어떤 조건이 수업을 내릴지 잘 모르겠습니다. 확실히 정적 정보로 클래스를 내리지 않아야합니다.

따라서 응용 프로그램이 실행되면 영역으로 들어가 새로운 클래스를 참조하여로드 된 클래스의 수가 올라가는 곳에서 대략 패턴을 기대할 수 있습니다.

그러나 두 가지가 이상하게 보입니다.

  1. 왜 그렇게 선형입니까?
  2. 왜 고원이 아닌가?

나는 그것이 위로 올라갈 것으로 예상하지만, 흔들리는 선에서, JVM이 이미 프로그램 참조의 대부분의 클래스를 이미로드함에 따라 증가에 따라 점점 줄어 듭니다. 대부분의 응용 프로그램에서 참조 된 유한 한 수업이 있습니다.

어떻게 든 즉시 새로운 수업을 만들고 있습니까?

동일한 디버거를 통해 더 간단한 테스트 앱을 실행하여 기본 케이스를 얻는 것이 좋습니다. 그런 다음 일부 디버그 정보를 뱉어내는 자신의 클래스 로더를 구현하거나 보고서를 작성하는 도구가있을 수 있습니다.

이 클래스가로드되는 것이 무엇인지 알아 내야합니다.

예, 일반적으로 메모리 누출입니다 (실제로 메모리를 직접 처리하지 않기 때문에 클래스 인스턴스 누출이 더 많습니다). 나는 전에이 과정을 거쳤으며 일반적으로 자체를 제거하지 않은 오래된 툴킷에 추가 된 청취자입니다.

구형 코드에서 청취자 관계는 "청취자"객체가 주위에 남아 있습니다. 나는 오래된 툴킷이나 많은 툴킷을 겪지 않은 툴킷을 살펴 봅니다. 나중에 JDK에서 실행되는 오랫동안 기존 라이브러리는 "리스너 제거"에 대한 요구 사항을 제거하는 참조 객체에 대해 알 수 있습니다.

또한 매번 창문을 재현하면 창문에 전화를 걸어 전화하십시오. 나는 당신이하지 않으면 그들이 사라지는 적이 없다고 생각합니다 (실제로 근접 설정에 처분이 있습니다).

스윙이나 JDK 청취자에 대해 걱정하지 마십시오. 모두 참조를 사용해야하므로 괜찮습니다.

사용 일식 메모리 분석기 복제 된 클래스 및 메모리 누출을 확인합니다. 동일한 클래스가 두 번 이상로드 될 수 있습니다.

문안 인사,마르쿠스

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top