2008-10-03 3 views
9

최근 VisualVM을 사용하여 작성한 osgi Java 응용 프로그램의 프로파일 링을 시작했습니다. 내가 알아챈 한가지는 애플리케이션이 (JMS를 통해) 클라이언트에 데이터를 보내기 시작할 때로드 된 클래스의 수가 일정한 비율로 증가하기 시작한다는 것입니다. 그러나 힙 크기와 PermGen 크기는 일정하게 유지됩니다. 데이터 전송을 중지 한 후에도 클래스 수는 결코 줄어들지 않습니다. 이것은 메모리 누출인가요? 로드 된 클래스는 어딘가에 저장해야하기 때문에 그것이라고 생각하지만 힙과 permgen은 몇 시간 동안 애플리케이션을 실행 한 후에도 절대 증가하지 않습니다.Java 응용 프로그램에서로드 된 클래스 수의 예상 메모리 누수

내 프로파일 응용 프로그램의 스크린 샷 here

답변

5

어떻게 든 새로운 클래스를 동적으로 생성하고 있습니까?

도움 주셔서 감사합니다. 나는 그 문제가 무엇인지 알아 냈다. 내 수업 중 하나에서 Jaxb를 사용하여 XML 문자열을 만들었습니다. 이렇게하면 JAXB는 리플렉션을 통해 새로운 클래스를 생성합니다.

그래서 JAXBContext가 힙에서 주위를 말하고 있지는 않지만 클래스가로드되었습니다.

나는 내 프로그램을 다시 실행했으며 예상대로 정상적인 고원을 본다.

+6

나는 새 클래스의 생성을 제거있어 방법을 물어 봐도 될까요? -이 문제를 해결하기 위해 노력하고 있으며 솔루션을 사용해보고 싶습니다. -Thanks – Ytsejammer

0

예, 그것은 일반적으로 메모리 누수의 이동을 위해 (우리가 정말 메모리에 직접 취급하지 않기 때문에, 그것은 클래스 인스턴스 누출의 더). 나는 이전에이 과정을 거쳤으며 대개는 청취자가 그것을 제거하지 않은 오래된 툴킷에 추가되었습니다.

이전 코드에서는 리스너 관계로 인해 "listener"객체가 계속 남아 있습니다. 나는 구형 툴킷이나 많은 레브를 통과하지 못한 툴킷을 살펴볼 것이다. 최신 JDK에서 실행되는 오래 동안 존재하는 라이브러리는 "Remove Listener"에 대한 요구 사항을 제거하는 참조 오브젝트에 대해 알고 있습니다.

또한 매번 다시 작성하면 창에서 dispose를 호출하십시오. 나는 당신이하지 않으면 그들이 떠날 것이라고 생각하지 않는다. (실제로는 가까이에 처분도있다.)

Swing 또는 JDK 리스너에 대해 걱정할 필요가 없으므로 모두 참조를 사용하여 괜찮습니다.

3

오해하지 않는 한, 여기서는 인스턴스가 아닌로드 된 클래스를 살펴 보겠습니다.

코드가 처음 클래스를 참조 할 때 JVM은 ClassLoader를 꺼내 클래스 파일에 대한 정보를 가져옵니다.

클래스를 언로드하는 조건이 확실하지 않습니다. 확실히 정적 정보를 가진 클래스를 언로드해서는 안됩니다.

여러분의 애플리케이션이 실행될 때 영역으로 들어가고 새로운 클래스를 참조하는 패턴과 비슷한 패턴이 예상되므로로드 된 클래스 수가 올라갈 것입니다.

그러나, 두 가지가 나에게 이상한 것 같다

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

JVM이 프로그램에서 참조하는 대부분의 클래스를 이미로드 했으므로 위쪽으로 트렌드가 올 것이지만 흔들린 선에서는 점점 더 가파르게 증가 할 것으로 예상됩니다. 내 말은, 대부분의 응용 프로그램에서 참조되는 클래스 수가 제한되어 있다는 것입니다.

어떻게 든 새로운 클래스를 동적으로 생성하고 있습니까?

동일한 디버거를 통해 간단한 테스트 앱을 실행하여 기준을 얻는 것이 좋습니다. 그런 다음 디버그 정보를 뱉어내는 ClassLoader를 구현하는 방법을 고려해 볼 수도 있고, 보고서를 작성하는 도구가있을 수도 있습니다.

로드 할 클래스를 파악해야합니다.

4

나는 당신의 문제가 바이트 코드 생성과 관련이 있다는 것을 기꺼이 믿는다.

많은 라이브러리는 CGLib, BCEL, Javasist 또는 Janino를 사용하여 런타임에 새 클래스의 바이트 코드를 생성 한 다음 제어 된 클래스 로더에서로드합니다. 이러한 클래스를 해제하는 유일한 방법은 클래스 로더에 대한 모든 참조를 해제하는 것입니다.

클래스 로더는 각 클래스에서 보유하므로 모든 클래스에 대한 참조도 해제하지 않아야 함을 의미합니다 [1]. 괜찮은 프로파일 러로 이들을 잡을 수 있습니다 (저는 Yourkit을 사용합니다 - 동일한 크기를 유지하면서 여러 클래스 로더 인스턴스를 검색하십시오)

JVM이 클래스를 기본적으로 언로드하지 않는다는 이유 중 하나가 있습니다 . (잘못) 정적 초기화 한 번만 실행될 것이라는 사실은 클래스가로드 될 때마다 실행 얻을 것입니다) 하역을 사용하려면 일부는 다음과 같은 옵션을 사용할 통과해야합니다.

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled 

는 (테스트를 JDK 1.5)

과도한 바이트 코드 생성은 좋지 않으므로 su ggest는 코드에서 범인을 찾고 생성 된 클래스를 캐시합니다. 빈번한 범죄자는 스크립팅 언어, 동적 프록시 (응용 프로그램 서버에서 생성 된 것 포함) 또는 거대한 Hibernate 모델 (이 경우에는 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
+0

JVM조차도 java.lang.reflect.Proxy에 대한 클래스를 생성하고 Field.get/set, Method.invoke 및 Constructor.newInstance (IIRC)를 워밍업합니다. –

+0

네, 그렇습니다. 생성 된 클래스는 여전히 반사 레이어에 캐시되므로 permgen 누출의 원인이되어서는 안됩니다. – ddimitrov

0

사용 Eclipse Memory Analyzer 중복 클래스와 메모리 누수를 확인 할 수 있습니다. 동일한 클래스가 두 번 이상로드 될 수도 있습니다.

안부, Markus