[java] Java 메모리 누출을 찾는 방법

Java에서 메모리 누수를 어떻게 찾습니까 (예 : JHat 사용)? JHat에서 힙 덤프를로드하여 기본 모양을 보았습니다. 그러나 루트 참조 ( ref ) 또는 호출 된 것을 찾을 수 있어야하는 방법을 이해하지 못합니다 . 기본적으로, 수백 메가 바이트의 해시 테이블 항목 ([java.util.HashMap $ Entry 또는 이와 유사한 것)이 있다고 말할 수 있지만,지도는 어디에서나 사용됩니다 … 큰지도를 검색 할 방법이 있습니까? 또는 대형 객체 트리의 일반적인 뿌리를 찾을 수 있습니까?

[편집] 좋아, 나는 지금까지 답변을 읽었지만 나는 싼 놈이라고 말하자 (JProfiler를 지불하는 것보다 JHat를 사용하는 방법을 배우는 데 더 관심이 있음을 의미 함). 또한 JHat은 JDK의 일부이므로 항상 사용 가능합니다. 물론 JHat을 사용하는 방법은 없지만 무차별 적 인 방법은 없지만 그럴 수는 없습니다.

또한 실제로 모든 맵 크기의 로깅을 추가 하고 누출을 알 수있을 정도로 오랫동안 실행할 수 있다고 생각하지 않습니다 .



답변

Java에서 메모리 누수를 찾기 위해 다음 접근법을 사용합니다. 나는 jProfiler를 큰 성공으로 사용했지만, 그래프 기능을 갖춘 모든 특수 도구 (diff는 그래픽 형식으로 분석하기가 더 쉽다)는 생각합니다.

  1. 모든 초기화가 완료되고 응용 프로그램이 유휴 상태 인 경우 응용 프로그램을 시작하고 “안정된”상태가 될 때까지 기다립니다.
  2. 캐시, DB 관련 초기화가 발생할 수 있도록 메모리 누수가 발생하는 것으로 의심되는 작업을 여러 번 실행하십시오.
  3. GC를 실행하고 메모리 스냅 샷을 만듭니다.
  4. 작업을 다시 실행하십시오. 작업의 복잡성과 처리되는 데이터 크기에 따라 작업을 여러 번 실행해야 할 수도 있습니다.
  5. GC를 실행하고 메모리 스냅 샷을 만듭니다.
  6. 2 개의 스냅 샷에 대해 diff를 실행하고 분석하십시오.

기본적으로 분석은 객체 유형에 의한 가장 큰 양의 차이에서 시작하여 추가 객체가 메모리에 달라 붙는 원인을 찾아야합니다.

여러 스레드에서 요청을 처리하는 웹 응용 프로그램의 경우 분석이 더 복잡해 지지만 일반적인 접근 방식은 여전히 ​​적용됩니다.

나는 응용 프로그램의 메모리 풋 프린트를 줄이기 위해 특별히 많은 프로젝트를 수행 했으며이 응용 프로그램 특정 조정 및 트릭 으로이 일반적인 접근 방식은 항상 잘 작동했습니다.


답변

질문자, 클릭에 응답하는 데 5 분이 걸리지 않는 도구를 사용하면 잠재적 인 메모리 누수를 훨씬 쉽게 찾을 수 있습니다.

사람들이 여러 도구를 제안하고 있기 때문에 (JDK 및 JProbe 시험에서 얻은 후에 시각적 wm 만 시도했습니다) Eclipse 플랫폼, 메모리 분석기 (때로는 SAP 메모리라고도 함)에 빌드 된 무료 / 오픈 소스 도구를 제안해야하지만 분석기)를 http://www.eclipse.org/mat/에서 이용할 수 있습니다 .

이 도구의 가장 멋진 점은 처음 열 때 힙 덤프를 인덱싱하여 각 객체에 대해 5 분을 기다리지 않고 보유 힙과 같은 데이터를 표시 할 수 있다는 것입니다 (거의 모든 작업은 내가 시도한 다른 도구보다 훨씬 빠릅니다) .

덤프를 열면 첫 번째 화면에 가장 큰 객체가있는 원형 차트가 표시되고 (계산 된 힙 계산) 하나는 안락을 위해 큰 객체로 빠르게 이동할 수 있습니다. 그것은 또한 내가 생각할 수있는 누출 가능성이 의심되는 찾기를 가지고 있지만 탐색이 충분했기 때문에 실제로 들어 가지 않았습니다.


답변

도구는 큰 도움이됩니다.

그러나 도구를 사용할 수없는 경우가 있습니다. 힙 덤프가 너무 커서 도구와 충돌하고 일부 프로덕션 환경에서 셸 액세스 권한 만있는 컴퓨터의 문제를 해결하려고합니다.

이 경우 hprof 덤프 파일을 처리하는 방법을 아는 것이 도움이됩니다.

BEGIN SITES를 찾으십시오. 이것은 어떤 객체가 가장 많은 메모리를 사용하고 있는지 보여줍니다. 그러나 객체는 유형별로만 묶이지 않습니다. 각 항목에는 “추적”ID도 포함됩니다. 그런 다음 해당 “TRACE nnnn”을 검색하여 객체가 할당 된 스택의 최상위 몇 프레임을 볼 수 있습니다. 종종 객체가 할당 된 위치를 확인하면 버그를 발견하고 완료됩니다. 또한 -Xrunhprof 옵션을 사용하여 스택에 기록되는 프레임 수를 제어 할 수 있습니다.

할당 사이트를 확인한 후 잘못된 것이 없으면 예상하지 못한 참조 체인을 찾기 위해 해당 라이브 오브젝트 중 일부에서 루트 오브젝트로 역방향 체인을 시작해야합니다. 이것은 도구가 실제로 도움이되는 곳이지만 손으로도 같은 일을 할 수 있습니다 (그렙으로). 루트 객체는 하나도 없습니다 (즉, 가비지 수집 대상이 아닌 객체). 스레드, 클래스 및 스택 프레임은 루트 객체의 역할을하며 이들이 참조하는 것은 수집 할 수 없습니다.

체인을 수행하려면 HEAP DUMP 섹션에서 불량 추적 ID가있는 항목을 찾으십시오. OBJ 또는 ARR 항목으로 이동하여 16 진수로 고유 한 오브젝트 ID를 표시합니다. 해당 ID의 모든 항목을 검색하여 객체에 대한 강력한 참조를 가진 사람을 찾으십시오. 누출이있는 곳을 알아낼 때까지 분기 된 각 경로를 뒤로 따르십시오. 도구가 왜 그렇게 편리한 지 알아?

정적 멤버는 메모리 누수에 대한 반복적 인 위반자입니다. 실제로 도구가 없어도 정적 Map 멤버의 코드를 살펴 보는 데 몇 분이 소요됩니다. 지도가 커질 수 있습니까? 항목을 정리 한 것이 있습니까?


답변

대부분의 경우 엔터프라이즈 응용 프로그램에서 제공된 Java 힙은 최대 12-16GB의 이상적인 크기보다 큽니다. NetBeans 프로파일 러가 이러한 큰 Java 앱에서 직접 작동하는 것이 어렵다는 것을 알았습니다.

그러나 보통 이것은 필요하지 않습니다. jdk와 함께 제공되는 jmap 유틸리티를 사용하여 “실시간”힙 덤프를 수행 할 수 있습니다. 즉, jmap은 GC를 실행 한 후 힙을 덤프합니다. 응용 프로그램에서 일부 작업을 수행하고 작업이 완료 될 때까지 기다린 다음 다른 “라이브”힙 덤프를 가져 오십시오. Eclipse MAT와 같은 도구를 사용하여 힙 덤프를로드하고, 히스토그램을 정렬하고, 증가한 오브젝트 또는 가장 높은 오브젝트를 확인하십시오. 이것이 실마리를 제공합니다.

su  proceeuser
/bin/jmap -dump:live,format=b,file=/tmp/2930javaheap.hrpof 2930(pid of process)

이 방법에는 한 가지 문제 만 있습니다. 라이브 옵션을 사용하더라도 대용량 힙 덤프는 개발 랩으로 전송하기에는 너무 크며 메모리 / RAM이 충분한 머신이 필요할 수 있습니다.

그것이 클래스 히스토그램이 그려지는 곳입니다. jmap 도구를 사용하여 라이브 클래스 히스토그램을 덤프 할 수 있습니다. 이 클래스는 메모리 사용에 대한 클래스 히스토그램 만 제공합니다. 기본적으로 참조를 연결하는 정보는 없습니다. 예를 들어 char 배열을 맨 위에 놓을 수 있습니다. 그리고 아래 어딘가에 String 클래스가 있습니다. 연결을 직접 그려야합니다.

jdk/jdk1.6.0_38/bin/jmap -histo:live 60030 > /tmp/60030istolive1330.txt

두 개의 힙 덤프를 사용하는 대신 위에서 설명한 것처럼 두 개의 클래스 히스토그램을 사용하십시오. 그런 다음 클래스 히스토그램을 비교하고 증가하는 클래스를 확인하십시오. Java 클래스를 애플리케이션 클래스와 연관시킬 수 있는지 확인하십시오. 이것은 꽤 좋은 힌트를 줄 것입니다. 다음은 두 개의 jmap 히스토그램 덤프를 비교하는 데 도움이되는 pythons 스크립트입니다. histogramparser.py

마지막으로 JConolse 및 VisualVm과 같은 도구는 시간이 지남에 따라 메모리 증가를 확인하고 메모리 누수가 있는지 확인하는 데 필수적입니다. 마지막으로 문제는 메모리 누수가 아닌 메모리 사용량 일 수 있습니다.이를 위해 GC 로깅을 사용하도록 설정하십시오. jstat와 같은 jdk 도구를 사용하여 GC 동작을 실시간으로 볼 수 있습니다.

jstat -gccause pid <optional time interval>

-jhat, jmap, Full GC, Humongous 할당, G1GC에 대한 Google의 다른 참조


답변

JProbe, YourKit, AD4J 또는 JRockit Mission Control과 같이 누출을 찾는 데 도움이되는 도구가 있습니다. 마지막은 내가 개인적으로 가장 잘 알고있는 것입니다. 좋은 도구를 사용하면 누수를 쉽게 식별 할 수있는 수준과 누수 대상이 할당 된 위치까지 드릴 다운해야합니다.

HashTables, Hashmaps 또는 이와 유사한 기능을 사용하면 Java에서 메모리를 전혀 누수 할 수있는 몇 가지 방법 중 하나입니다. 손으로 누출을 찾아야한다면 나는 정기적으로 내 HashMaps의 크기를 인쇄하고 거기에서 항목을 추가하고 삭제하는 것을 잊어 버렸습니다.


답변

글쎄, 맵을 수정할 때 맵 크기의 로깅을 추가 한 다음, 맵이 적당한 크기 이상으로 커지는 로그를 검색하는 최첨단 솔루션이 항상 있습니다.


답변

NetBeans에는 내장 프로파일 러가 있습니다.