Java 메모리 누전 검출 방법
Java(예를 들어 JHat 사용)에서 메모리 누수는 어떻게 발견합니까?힙 덤프를 JHat에 로드하여 기본적인 내용을 확인하려고 했습니다.그런데 어떻게 루트 레퍼런스(ref)나 어떤 것을 찾을 수 있는지 모르겠습니다.기본적으로 수백 MB의 해시 테이블 엔트리가 있음을 알 수 있습니다([java.util]).HashMap$Entry와 같은 것)이지만 맵은 어디에서나 사용되고 있습니다.큰 지도를 검색하거나 큰 객체 트리의 일반적인 뿌리를 찾을 수 있는 방법이 있습니까?
[편집] 네, 지금까지 답을 읽었지만, 저는 싸구려라고 합시다(JProfiler를 사는 것보다 JHAT를 배우는 것에 더 관심이 있습니다).또한 JHat은 JDK의 일부이므로 항상 사용할 수 있습니다.물론 JHAT에는 폭력 말고는 방법이 없지만, 그런 일이 있을 수 있다는 것을 믿을 수가 없다.
또, 실제로 변경(모든 지도 사이즈의 로그 추가)을 실시해, 누수를 눈치챌 수 있을 때까지의 시간을 단축할 수 없을 것 같지 않습니다.
Java에서 메모리 누수를 찾기 위해 다음과 같은 방법을 사용합니다.저는 jProfiler를 성공적으로 사용했지만, 그래프 기능을 갖춘 전문 도구(그래픽 형태로 분석하기 더 쉬움)라면 어떤 것이든 작동한다고 생각합니다.
- 애플리케이션을 기동해, 모든 초기화가 완료해, 애플리케이션이 아이돌 상태가 될 때까지 기다립니다.
- 메모리 누수가 의심되는 작업을 여러 번 실행하여 캐시, DB 관련 초기화가 수행되도록 합니다.
- GC를 실행하고 메모리 스냅샷을 만듭니다.
- 작업을 다시 실행합니다.조작의 복잡성과 처리되는 데이터의 크기에 따라서는, 조작을 몇번이나 몇번이나 실행할 필요가 있는 경우가 있습니다.
- GC를 실행하고 메모리 스냅샷을 만듭니다.
- 2개의 스냅샷에 대해 diff를 실행하고 분석합니다.
기본적으로 분석은 예를 들어 객체 유형에 의한 가장 큰 양의 차이에서 시작하여 이러한 추가 객체가 메모리에 남아 있는 원인을 찾아야 합니다.
여러 스레드에서 요청을 처리하는 웹 애플리케이션의 경우 분석이 더 복잡하지만 일반적인 접근 방식이 여전히 적용됩니다.
특히 애플리케이션의 메모리 용량을 줄이기 위해 많은 프로젝트를 수행했으며, 애플리케이션 고유의 조정과 트릭을 통해 이 일반적인 접근 방식이 항상 잘 작동했습니다.
질문입니다만, 클릭에 응답하는 데 5분이 걸리지 않는 툴을 사용하면 메모리 누수 가능성을 쉽게 찾을 수 있습니다.
사람들이 몇 가지 툴을 제안하고 있기 때문에(JDK와 JProbe의 트라이얼에서 입수했기 때문에 비주얼 WM만 시도했습니다), Eclipse 플랫폼 상에 구축된 무료 오픈소스 툴인 메모리아나라이저(SAP 메모리아나라이저라고도 불립니다)를 제안하고 싶습니다.
이 툴의 정말 멋진 점은 처음 열었을 때 힙 덤프를 인덱싱하여 각 오브젝트에 대해 5분 동안 기다리지 않고 유지된 힙과 같은 데이터를 표시할 수 있었다는 것입니다(거의 모든 작업이 다른 툴보다 훨씬 빨랐습니다).
덤프를 열면 첫 번째 화면에 가장 큰 개체(유지된 힙 수)가 있는 원형 차트가 표시되고, 쉽게 사용할 수 있도록 크기가 너무 큰 개체로 빠르게 이동할 수 있습니다.누출 용의자를 찾을 수 있는 기능도 있어 편리하지만 내비게이션으로 충분했기 때문에 자세히 알아보지 못했습니다.
도구는 큰 도움이 됩니다.
다만, 툴을 사용할 수 없는 경우가 있습니다.히프 덤프가 너무 커서 툴이 크래시되거나 셸 액세스만 가능한 일부 실가동 환경에서 머신의 트러블 슈팅을 시도하거나 하는 등입니다.
이 경우 hprof 덤프 파일에 대해 아는 것이 도움이 됩니다.
SITES BEGIN을 찾습니다.이것은 어떤 오브젝트가 메모리를 가장 많이 사용하는지를 보여줍니다.그러나 개체는 유형별로만 분류되지 않습니다. 각 항목에는 "추적" ID도 포함됩니다.그런 다음 "TRACE nnn"을 검색하여 개체가 할당된 스택의 상위 몇 개의 프레임을 볼 수 있습니다.오브젝트가 할당되어 있는 장소를 확인하면 버그가 발견되어 종료되는 경우가 많습니다.또한 -Xrunhprof 옵션을 사용하여 스택에 기록되는 프레임 수를 제어할 수 있습니다.
할당 사이트를 확인했는데 아무런 문제가 없는 경우 라이브 개체에서 루트 개체로 역방향 체인을 시작해야 예기치 않은 참조 체인을 찾을 수 있습니다.툴이 도움이 됩니다만, 같은 작업을 수작업으로 실시할 수 있습니다(GREP도 마찬가지입니다.루트 개체(즉, 가비지 컬렉션의 대상이 아닌 개체)가 하나만 있는 것은 아닙니다.스레드, 클래스 및 스택프레임은 루트오브젝트로서 기능합니다.이러한 프레임이 강하게 참조하는 것은 수집되지 않습니다.
체인을 실행하려면 HEAP DUMP 섹션에서 잘못된 트레이스 ID를 가진 엔트리를 찾습니다.그러면 OBJ 또는 ARR 엔트리가 나타납니다.이 엔트리는 하나의 객체 ID를 16진수로 나타냅니다.해당 ID의 모든 항목을 검색하여 개체에 대한 강력한 참조를 가진 사용자를 찾습니다.물이 새는 곳을 알아낼 때까지 각각의 경로를 따라 뒤로 가세요.도구가 편리한 이유를 알겠습니까?
스태틱 멤버는 메모리 누수의 재범입니다.실제로 툴이 없어도 정적 맵 구성원을 위해 코드를 몇 분 동안 살펴볼 가치가 있습니다.지도는 커질 수 있나요?엔트리를 정리하는 것이 있습니까?
대부분의 경우 엔터프라이즈 애플리케이션에서는 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
2개의 힙 덤프를 사용하는 대신 위와 같이 2개의 클래스 히스토그램을 사용합니다.그런 다음 클래스 히스토그램을 비교하여 증가하는 클래스를 확인합니다.Java 클래스를 응용 프로그램 클래스에 연결할 수 있는지 확인하십시오.이게 꽤 좋은 힌트가 될 거예요.다음은 두 jmap 히스토그램 덤프를 비교하는 데 도움이 되는 비단뱀 스크립트입니다.히스토그램파서화이
마지막으로 JConolse 및 VisualVm과 같은 툴은 시간에 따른 메모리 증가 및 메모리 누수 여부를 확인하는 데 필수적입니다.마지막으로 메모리 누수가 아니라 메모리 사용량이 많은 문제가 발생할 수 있습니다.GC 로깅을 활성화하려면 GC 로깅을 활성화하고 G1GC와 같은 고급 압축 GC를 사용합니다.또한 jstat 등의 jdk 도구를 사용하여 GC 동작을 실시간으로 확인할 수 있습니다.
jstat -gccause pid <optional time interval>
기타 -jhat, jmap, Full GC, Humongous allocation, G1GC에 대한 구글 검색 참조
JProbe, YourKit, AD4J 또는 JRockit Mission Control과 같이 누출을 찾는 데 도움이 되는 도구가 있습니다.마지막은 제가 개인적으로 가장 잘 알고 있는 것입니다.어떤 좋은 툴이든 어떤 누출이 있는지, 그리고 누출된 물체가 어디에 할당되어 있는지 쉽게 식별할 수 있는 수준까지 드릴다운할 수 있어야 합니다.
HashTables, Hashmaps 등을 사용하는 것은 Java에서 메모리를 완전히 누출할 수 있는 몇 안 되는 방법 중 하나입니다.만약 리크를 손으로 찾아야 한다면 해시맵의 사이즈를 주기적으로 인쇄하고 거기서 아이템을 추가한 것을 찾아 삭제하지 않습니다.
맵을 변경할 때 맵 크기의 로깅을 추가하고 적절한 크기를 초과하는 맵의 로그를 검색하는 기술 수준이 낮은 솔루션은 항상 존재합니다.
NetBeans에는 프로파일러가 내장되어 있습니다.
할당을 추적하는 메모리 프로파일러를 사용해야 합니다.JProfiler를 보세요.JProfiler의 "Heap walker" 기능은 훌륭하며 주요 Java IDE와 모두 통합되어 있습니다.무료는 아니지만, 그렇게 비싼 것도 아닙니다.즉, 500달러 상당의 시간을 낭비하고, 덜 정교한 툴로 누출을 찾기 위해 안간힘을 쓸 것입니다.
가비지 콜렉터를 여러 번 호출한 후 메모리 사용량 크기를 측정하여 확인할 수 있습니다.
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");
}
}
출력 수가 같으면 응용 프로그램에서 메모리 누수는 발생하지 않지만 메모리 사용량(증가) 간에 차이가 있는 경우 프로젝트에서 메모리 누수가 발생한 것입니다.예를 들어 다음과 같습니다.
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
스트림이나 소켓 등의 동작으로 메모리를 해방하는 데 시간이 걸릴 수 있습니다.첫 번째 출력으로 판단하지 말고 특정 시간 내에 테스트해야 합니다.
JProfiler를 사용한 메모리 누전 검출에 관한 화면 캐스트를 확인해 주세요.@Dima Malenko Answer의 시각적 설명입니다.
주의: JProfiler는 프리웨어는 아니지만 트라이얼 버전은 현재 상황에 대처할 수 있습니다.
우리 대부분은 이미 코드를 작성하기 위해 Eclipse를 사용하고 있기 때문에, Eclipse의 MAT(메모리 분석 도구)를 사용하는 것은 어떨까요?아주 잘 작동한다.
Eclipse MAT는 분석 도구를 제공하는 Eclipse IDE용 플러그인 세트입니다.heap dumps
에서 Java를 식별하기 memory problems
이치노
이를 통해 개발자는 다음과 같은 기능을 통해 메모리 누수를 찾을 수 있습니다.
- 메모리 스냅샷 취득(Heap Dump)
- 히스토그램
- 유지된 힙
- 도미네이터 트리
- GC 루트에 대한 경로 탐색
- 인스펙터
- 공통 메모리 안티 패턴
- 오브젝트 쿼리 언어
최근 어플리케이션 메모리 누수에 대처했습니다.여기서의 경험을 공유하다
가비지 컬렉터는 참조되지 않은 개체를 정기적으로 제거하지만 아직 참조 중인 개체는 수집하지 않습니다.여기서 메모리 누수가 발생할 수 있습니다.
다음은 참조된 개체를 찾는 몇 가지 옵션입니다.
- 「」를 사용합니다.
jvisualvm
에 있습니다.JDK/bin
더 folder
옵션: 히프 영역 감시
히프 영역이 계속 증가하고 있는 경우는, 확실히 메모리 누수가 발생하고 있습니다.
, 을 하세요.memory sampler
아래sampler
.
를 하여 Java 힙 .
jmap
에서도 이용 합니다).JDK/bin
의 다른 시간 내)에 있습니다.jmap -histo <pid> > histo1.txt
여기서 객체 참조를 분석할 수 있습니다.일부 개체가 가비지 수집되지 않은 경우 메모리 누수 가능성이 있습니다.
메모리 누수의 가장 일반적인 원인 중 몇 가지를 읽어보실 수 있습니다.Java에서의 메모리 누수에 대해서
언급URL : https://stackoverflow.com/questions/40119/how-to-find-a-java-memory-leak
'programing' 카테고리의 다른 글
IntelliJ에서 이 기호는 무엇을 의미합니까? ('J'가 들어간 파일 이름의 왼쪽 아래 모서리에 있는 빨간색 원) (0) | 2022.09.03 |
---|---|
Java: 문자열에서 일치 위치를 가져오는 방법? (0) | 2022.09.03 |
Vue js에서 여러 페이지(컴포넌트)를 동적으로 사용 (0) | 2022.09.03 |
Vue 컴포넌트 - 렌더링 위치가 잘못됨 (0) | 2022.09.03 |
java.nio. 파일을 가져옵니다.java.io로부터의 패스 오브젝트파일 (0) | 2022.09.03 |