이것은 내가 지금 몇 달 동안 추적하려고 시도한 문제입니다. xml 피드를 처리하고 결과를 데이터베이스에 저장하는 Java 앱이 실행 중입니다. 추적하기 매우 어려운 간헐적 인 리소스 문제가있었습니다.
배경 : 프로덕션 박스 (문제가 가장 눈에 띄는 곳)에서 저는 박스에 특별히 접근 할 수없고 Jprofiler를 실행할 수 없습니다. 이 상자는 centos 5.2, tomcat6 및 java 1.6.0.11을 실행하는 64 비트 쿼드 코어, 8GB 머신입니다. 이 java-opts로 시작합니다.
JAVA_OPTS="-server -Xmx5g -Xms4g -Xss256k -XX:MaxPermSize=256m -XX:+PrintGCDetails -
XX:+PrintGCTimeStamps -XX:+UseConcMarkSweepGC -XX:+PrintTenuringDistribution -XX:+UseParNewGC"
기술 스택은 다음과 같습니다.
- Centos 64 비트 5.2
- 자바 6u11
- 톰캣 6
- Spring / WebMVC 2.5
- 최대 절전 모드 3
- 석영 1.6.1
- DBCP 1.2.1
- MySQL 5.0.45
- Ehcache 1.5.0
- (물론 다른 종속성, 특히 자카르타-커먼스 라이브러리)
문제를 재현 할 수있는 가장 가까운 방법은 메모리 요구 사항이 낮은 32 비트 컴퓨터입니다. 내가 통제 할 수 있다는 것. 필자는 JProfiler를 사용하여이 문제를 조사하고 많은 성능 문제를 해결했습니다 (동기화 문제, xpath 쿼리 사전 컴파일 / 캐싱, 스레드 풀 감소, 불필요한 최대 절전 모드 사전 가져 오기 제거, 처리 중 과도한 "캐시 워밍"제거).
각각의 경우에 프로파일 러는 이러한 것들이 어떤 이유로 든 엄청난 양의 리소스를 차지하는 것으로 나타 났으며 변경 사항이 들어 오면 더 이상 기본 리소스 돼지가 아님을 보여주었습니다.
문제 : JVM이 메모리 사용 설정을 완전히 무시하고 모든 메모리를 채우고 응답하지 않는 것 같습니다. 이는 정기 폴링 (5 분 기준 및 1 분 재시도)을 기대하는 최종 고객과 상자가 응답하지 않는다는 알림을 지속적으로 받고 다시 시작해야하는 운영 팀의 문제입니다. 이 상자에는 다른 중요한 실행이 없습니다.
문제 는 가비지 수집 인 것으로 보입니다 . ConcurrentMarkSweep (위에서 언급 한대로) 수집기를 사용하고 있습니다. 원래 STW 수집기가 JDBC 시간 초과를 일으키고 점점 느려졌 기 때문입니다. 로그에 따르면 메모리 사용량이 증가함에 따라 cms 오류가 발생하기 시작하고 원래의 stop-the-world 수집기로 돌아가서 제대로 수집되지 않는 것으로 보입니다.
그러나 jprofiler로 실행하면 "Run GC"버튼은 증가하는 풋 프린트를 보여주지 않고 메모리를 깔끔하게 정리하는 것처럼 보이지만 jprofiler를 프로덕션 박스에 직접 연결할 수없고 검증 된 핫스팟 해결이 작동하지 않는 것 같습니다. 가비지 컬렉션 블라인드 튜닝의 부두가 남았습니다.
내가 시도한 것 :
- 핫스팟 프로파일 링 및 수정.
- STW, 병렬 및 CMS 가비지 수집기를 사용합니다.
- 최소 / 최대 힙 크기를 1 / 2,2 / 4,4 / 5,6 / 6 증분으로 실행합니다.
- 최대 1Gb까지 256M 단위로 permgen 공간으로 실행됩니다.
- 위의 많은 조합.
- 또한 JVM [tuning reference] (http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html)을 참조했지만이 동작을 설명하는 내용이나 _which_ 조정의 예를 찾을 수 없습니다. 이와 같은 상황에서 사용할 매개 변수입니다.
- 또한 오프라인 모드에서 jprofiler를 시도하여 jconsole, visualvm과 연결했지만 내 gc 로그 데이터를 방해하는 것을 찾을 수없는 것 같습니다.
안타깝게도 문제는 산발적으로 나타나고 예측할 수없는 것처럼 보이며 문제없이 며칠 또는 일주일 동안 실행할 수 있거나 하루에 40 번 실패 할 수 있으며 지속적으로 잡을 수있는 유일한 것은 가비지 컬렉션이 작동하고 있습니다.
사람에 관한 조언을 제공 할 수 있습니다 :
a)는 JVM (8 개) 물리적 공연과 미만 6에서 최대 출력으로 구성 스왑 공간 2GB의 사용 이유는
사실을 설명하는 것이 B) GC 튜닝에 대한 참조 또는 적절한 예제를 제공합니다 고급 컬렉션을 사용할 때와 어떤 종류의 설정을 사용하는지.
c) 가장 일반적인 자바 메모리 누수에 대한 참조 (저는 주장되지 않은 참조를 이해하지만 라이브러리 / 프레임 워크 수준에서 의미하거나 해시 맵과 같은 데이터 구조에서 더 이질적인 것을 의미합니다).
제공 할 수있는 모든 통찰력에 감사드립니다.
Emil H 편집 :
1) 예, 제 개발 클러스터는 미디어 서버까지 프로덕션 데이터의 미러입니다. 가장 큰 차이점은 32/64 비트와 사용 가능한 RAM의 양으로, 쉽게 복제 할 수 없지만 코드와 쿼리 및 설정은 동일합니다.
2) JaxB에 의존하는 레거시 코드가 있지만 스케줄링 충돌을 피하기 위해 작업을 재정렬 할 때 하루에 한 번 실행되기 때문에 일반적으로 해당 실행이 제거되었습니다. 기본 파서는 java.xml.xpath 패키지를 호출하는 XPath 쿼리를 사용합니다. 하나는 쿼리가 미리 컴파일되지 않았고 두 개는 하드 코딩 된 문자열에 있었기 때문에 이것은 몇 가지 핫스팟의 소스였습니다. 스레드 세이프 캐시 (해시 맵)를 만들고 xpath 쿼리에 대한 참조를 최종 정적 문자열로 팩터링하여 리소스 소비를 크게 줄였습니다. 쿼리는 여전히 처리의 많은 부분을 차지하지만 애플리케이션의 주요 책임이기 때문입니다.
3) 추가 참고 사항, 다른 주요 소비자는 JAI의 이미지 작업 (피드에서 이미지 재 처리)입니다. 나는 자바의 그래픽 라이브러리에 익숙하지 않지만 내가 발견 한 것에서 그것들은 특별히 새지 않습니다.
(지금까지 답변 해 주셔서 감사합니다, 여러분!)
업데이트 :
VisualVM을 사용하여 프로덕션 인스턴스에 연결할 수 있었지만 GC 시각화 / run-GC 옵션을 비활성화했습니다 (로컬에서 볼 수는 있지만). 흥미로운 점 : VM의 힙 할당은 JAVA_OPTS를 따르고 있으며 실제 할당 된 힙은 1-1.5 기가 편안하게 앉아 있으며 누출되지 않는 것처럼 보이지만 상자 수준 모니터링은 여전히 누출 패턴을 보여 주지만 VM 모니터링에 반영되지 않습니다. 이 상자에서 실행중인 다른 항목이 없어서 당황합니다.