Java 메모리 누출을 찾는 방법
Java에서 메모리 누수를 어떻게 찾습니까 (예 : JHat 사용)? JHat에서 힙 덤프를로드하여 기본 모양을 보았습니다. 그러나 루트 참조 ( ref ) 또는 호출 된 것을 찾을 수 있어야하는 방법을 이해하지 못합니다 . 기본적으로 수백 메가 바이트의 해시 테이블 항목 ([java.util.HashMap $ Entry 또는 이와 유사한 것)이 있다고 말할 수 있지만,지도는 어디에서나 사용됩니다 ... 큰지도를 검색 할 방법이 있습니까? 또는 대형 객체 트리의 일반적인 뿌리를 찾을 수 있습니까?
[편집] 좋아, 나는 지금까지 답변을 읽었지만 나는 싼 놈이라고 말하자 (JProfiler를 지불하는 것보다 JHat를 사용하는 방법을 배우는 데 더 관심이 있음을 의미 함). 또한 JHat은 JDK의 일부이므로 항상 사용 가능합니다. 물론 JHat을 사용하는 방법은 없지만 무차별 적 인 방법은 없지만 그럴 수는 없습니다.
또한 실제로 모든 맵 크기의 로깅을 추가 하고 누출을 알 수있을 정도로 오랫동안 실행할 수 있다고 생각하지 않습니다 .
Java에서 메모리 누수를 찾기 위해 다음 접근법을 사용합니다. 나는 jProfiler를 큰 성공으로 사용했지만, 그래프 기능을 갖춘 모든 특수 도구 (diff는 그래픽 형식으로 분석하기가 더 쉽다)는 생각합니다.
- 모든 초기화가 완료되고 응용 프로그램이 유휴 상태 인 경우 응용 프로그램을 시작하고 "안정된"상태가 될 때까지 기다립니다.
- 캐시, DB 관련 초기화가 발생할 수 있도록 메모리 누수가 발생하는 것으로 의심되는 작업을 여러 번 실행하십시오.
- GC를 실행하고 메모리 스냅 샷을 만듭니다.
- 작업을 다시 실행하십시오. 작업의 복잡성과 처리되는 데이터 크기에 따라 작업을 여러 번 실행해야 할 수도 있습니다.
- GC를 실행하고 메모리 스냅 샷을 만듭니다.
- 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
Finally tools like JConolse and VisualVm are essential to see the memory growth over time, and see if there is a memory leak. Finally sometimes your problem may not be a memory leak , but high memory usage.For this enable GC logging;use a more advanced and new compacting GC like G1GC; and you can use jdk tools like jstat to see the GC behaviour live
jstat -gccause pid <optional time interval>
Other referecences to google for -jhat, jmap, Full GC, Humongous allocation, G1GC
There are tools that should help you find your leak, like JProbe, YourKit, AD4J or JRockit Mission Control. The last is the one that I personally know best. Any good tool should let you drill down to a level where you can easily identify what leaks, and where the leaking objects are allocated.
Using HashTables, Hashmaps or similar is one of the few ways that you can acually leak memory in Java at all. If I had to find the leak by hand I would peridically print the size of my HashMaps, and from there find the one where I add items and forget to delete them.
Well, there's always the low tech solution of adding logging of the size of your maps when you modify them, then search the logs for which maps are growing beyond a reasonable size.
NetBeans has a built-in profiler.
You really need to use a memory profiler that tracks allocations. Take a look at JProfiler - their "heap walker" feature is great, and they have integration with all of the major Java IDEs. It's not free, but it isn't that expensive either ($499 for a single license) - you will burn $500 worth of time pretty quickly struggling to find a leak with less sophisticated tools.
You can find out by measuring memory usage size after calling garbage collector multiple times:
Runtime runtime = Runtime.getRuntime();
while(true) {
...
if(System.currentTimeMillis() % 4000 == 0){
System.gc();
float usage = (float) (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
System.out.println("Used memory: " + usage + "Mb");
}
}
If the output numbers were equal, there is no memory leak in your application, but if you saw difference between the numbers of memory usage (increasing numbers), there is memory leak in your project. For example:
Used memory: 14.603279Mb
Used memory: 14.737213Mb
Used memory: 14.772224Mb
Used memory: 14.802681Mb
Used memory: 14.840599Mb
Used memory: 14.900841Mb
Used memory: 14.942261Mb
Used memory: 14.976143Mb
Note that sometimes it takes some time to release memory by some actions like streams and sockets. You should not judge by first outputs, You should test it in a specific amount of time.
참고URL : https://stackoverflow.com/questions/40119/how-to-find-a-java-memory-leak
'Programming' 카테고리의 다른 글
리소스가 없습니다-Theme.AppCompat.Light.DarkActionBar (0) | 2020.06.22 |
---|---|
IEqualityComparer의 차이점은 무엇입니까 (0) | 2020.06.22 |
자바 스크립트 node.js next () (0) | 2020.06.21 |
도커 컨테이너로 호스트 포트 전달 (0) | 2020.06.21 |
컨테이너에서 배경 이미지를 회전시키는 방법은 무엇입니까? (0) | 2020.06.21 |