JVM 메모리 누수 분석 (역사상 가장 완벽 함)

기사가 매우 길기 때문에 수집하고 천천히 읽는 것이 좋습니다 비고 : 지속적으로 업데이트 중 ...

큰 공장에 들어가고, 구조를 업그레이드하고, 높은 급여를받는 데 필요한 고전적인 책과 자료 :


권장 사항 2 : 월급이 50,000 이상인 2021 년 봄 신입 사원을위한 일반적인 인터뷰 질문 목록

다음 인터뷰 질문을 받으십시오. 2021 년 봄 신입 사원의 월급이 50,000 이상 (강력합니다!) 알리, Jingdong, Meituan, Toutiao ... 선택하고 마음대로 옆으로 걸어! ! !
자바 기초
1 : JVM 인터뷰 질문 (역사상 최강, 지속적인 업데이트, hematemesis 추천) https://www.cnblogs.com/crazymakercircle/p/14365820.html
2 : 자바 기본 인터뷰 질문 (역사상 가장 완전하고 지속적인 업데이트, hematemesis 추천) https://www.cnblogs.com/crazymakercircle/p/14366081.html
3 : 교착 상태 인터뷰 질문 (역사상 가장 강력하며 지속적으로 업데이트 됨) [https://www.cnblogs.com/crazymakercircle/p/14323919.html]
4 : 디자인 패턴 인터뷰 질문 (역사상 가장 포괄적 인, 지속적인 업데이트, hematemesis 추천) https://www.cnblogs.com/crazymakercircle/p/14367101.html
5 : 건축 설계 인터뷰 질문 (역사상 가장 포괄적 인, 지속적인 업데이트, hematemesis 추천) https://www.cnblogs.com/crazymakercircle/p/14367907.html
또한 닦고 닦아야하는 10 개 이상의 인터뷰 질문 이 있습니다. 자세한 내용은 【Crazy Maker Circle High Concurrency Catalog를 참조하세요.

권장 사항 3 : Crazy Maker Circle springCloud 높은 동시성 시리즈

springCloud 고품질 블로그 게시물
nacos 실제 전투 (역사상 가장 완벽한 전투) sentinel (역사상 가장 완벽한 + 입문 튜토리얼)
springcloud + webflux 높은 동시성 전투 Webflux (역사상 가장 완벽 함)
SpringCloud 게이트웨이 (역사상 가장 완벽 함)
이 있습니다 10 개 +의 기사 브러시 것이다가, 브러쉬 될 것입니다 고품질 보웬의 자세한 내용은 【Crazy Maker Circle High Concurrency Catalog를 참조하세요.

JVM 성능 최적화 인터뷰 질문

JVM 메모리 영역의 일반적인 문제

Java에서 잠시 메모리 누수가 있습니까?

자바 메모리 할당?

Java 힙의 구조는 무엇입니까?

힙의 Perm Gen 공간은 무엇입니까?

각 버전의 메모리 영역의 변경 사항을 간략하게 설명하십시오.

각 영역의 역할에 대해 이야기를 나누시겠습니까?

JVM 실행 하위 시스템의 일반적인 문제

자바 클래스 로딩 프로세스?

JVM 로딩 클래스 파일의 원리와 메커니즘 설명 클래스 로더 란?

클래스 로더는 무엇입니까?

클래스 로더 부모 위임 모델 메커니즘?

가비지 수집에 대해 자주 묻는 질문

GC 란 무엇입니까?

GC가있는 이유는 무엇입니까?

Java 가비지 수집 메커니즘을 간략하게 설명 하시겠습니까?

물체가 살아 있는지 판단하는 방법은 무엇입니까?

쓰레기 수거의 장점과 원리, 재활용 메커니즘의 두 가지 유형을 고려?

가비지 수집기의 기본 원리는 무엇입니까?

가비지 수집기가 메모리를 즉시 회수 할 수 있습니까?

가비지 수집을 위해 가상 머신에 사전에 알리는 방법이 있습니까?

딥 카피와 얕은 카피?

System.gc () 및 Runtime.gc ()는 무엇을합니까?

개체의 참조가 null로 설정되면 가비지 수집기가 개체가 차지하는 메모리를 즉시 해제합니까?

분산 가비지 수집 (DGC)이란 무엇입니까?

어떻게 작동합니까?

직렬 수집기와 처리량 수집기의 차이점은 무엇입니까?

Java에서 객체는 언제 가비지 수집 될 수 있습니까? Minor GC 및 Major GC를 간략하게 설명 하시겠습니까? JVM의 영구 생성에서 가비지 콜렉션이 발생합니까? Java에서 가비지 수집 방법은 무엇입니까?

성능 최적화 일반적인 문제

이해하는 성능 평가 및 테스트 지표에 대해 알려주세요.

일반적으로 사용되는 성능 최적화 방법은 무엇입니까?

GC 튜닝이란 무엇입니까?

JVM 튜닝 도구

Jconsole , jProfile , VisualVM

Jconsole : jdk는 간단한 기능과 함께 제공되지만 시스템에 특정 부하가있을 때 사용할 수 있습니다. 가비지 수집 알고리즘에 대한 매우 상세한 추적이 있습니다. 자세한 내용은 여기 를 참조 하십시오

JProfiler : 상용 소프트웨어, 지불해야합니다. 강한. 자세한 내용은 여기 를 참조 하십시오

VisualVM : JDK는 JProfiler와 유사한 강력한 기능을 제공합니다. 권하다.

JVisualVM의 예비 ​​연구

VisualVM은 JDK6.0 업데이트 7에 포함 된 Netbeans의 프로필 하위 프로젝트입니다 (Java 시작시 특정 매개 변수가 필요하지 않으며 모니터링 도구는 bin / jvisualvm.exe에 있음). 스레드, 메모리 상태, 메서드의 CPU 시간과 메모리의 개체, GC 된 개체, 할당 된 스택의 반대보기 (예 : 100 개의 문자열 개체에 의해 할당 된 개체)를 봅니다.

JDK_HOME / bin (기본적으로 C : \ Program Files \ Java \ jdk1.6.0_13 \ bin) 아래에 jvisualvm.exe 파일이 있습니다. 더블 클릭하여 엽니 다.이 소프트웨어는 UI에서 다음을 기반으로 개발되었습니다. NetBeans.

원격 및 로컬 모니터링을 수행 할 수 있습니다. 원격 모니터링은 아래에서 언급 할 jmx를 열어야합니다.

기본 페이지는 다음과 같습니다.

img

왼쪽은 로컬과 원격으로 나뉩니다. 로컬에서 VisualVM 스레드를 두 번 클릭하면 다음 모니터링 콘텐츠를 볼 수 있습니다.

img

구체적인 소개는 다음을 참조하십시오.

http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/

VisualVM은 필요에 따라 다른 플러그인을 설치할 수 있습니다. 각 플러그인은 서로 다른 포커스를 가지고 있습니다. 일부는 주로 GC를 모니터링하고 일부는 주로 메모리를 모니터링하고 일부는 스레드를 모니터링합니다.
여기에 사진 설명 삽입
설치하는 방법:

1. 메인 메뉴에서 "도구"> "플러그인"을 선택하십시오. 2. "사용 가능한 플러그인"탭에서 플러그인의 "설치"확인란을 선택합니다. "설치"를 클릭하십시오. 3. 플러그인 설치 절차를 단계별로 완료하십시오.

여기에서는 Eclipse (pid 22296)를 예로 들어 보겠습니다. 두 번 클릭하여 직접 확장합니다. 메인 인터페이스에는 system과 jvm의 두 가지 주요 내용이 표시됩니다. 오른쪽 하단에있는 jvm 매개 변수 및 시스템 속성을 클릭하여 자세한 내용을 참조하십시오. . 매개 변수에 대한 자세한 내용은
여기에 사진 설명 삽입
VisualVM과 너무 많은 플러그인이 있기 때문에, 나는 주로 여기에 세 가지를 소개합니다 내가 주로 몇 가지 사용합니다. 모니터링, 스레딩, 및 Visual GC의
. 모니터링을 모니터링 홈페이지는 실제로 CPU, 메모리, 클래스의 그래프입니다 , 및 thread.
여기에 사진 설명 삽입
스레드와 jconsole 함수 사이에는 큰 차이가 없습니다.
여기에 사진 설명 삽입
Visual GC는 자주 사용되는 함수입니다. 함수는 gc 주파수와 함께 젊은 세대와 이전 세대의 메모리 변화를 명확하게 볼 수 있습니다. gc 시간.
여기에 사진 설명 삽입
위의 기능은 jconsole에서도 거의 사용할 수 있습니다. VisualVM은보다 포괄적이고 직관적입니다. 또한 VisualVM의 다른 많은 기능으로 덤프 메모리 스냅
샷을 분석하고 스레드 스냅 샷을 덤프하고 분석 할 수 있으며 다른 많은 플러그-인이 있습니다. 탐색 할 수있는 기능
여기에 사진 설명 삽입

실제 전투

메모리 누수 데모 시뮬레이션 준비

1. 정적 변수 HashMap 정의

2. 세그먼트로 개체를 생성하고 HashMap에 추가

코드는 다음과 같습니다.

import java.util.HashMap;
import java.util.Map;
public class CyclicDependencies {
    //声明缓存对象
    private static final Map map = new HashMap();
    public static void main(String args[]){
        try {
            Thread.sleep(10000);//给打开visualvm时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //循环添加对象到缓存
        for(int i=0; i<1000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("first");
        //为dump出堆提供时间
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<1000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("second");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<3000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("third");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<4000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("forth");
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("qqqq");
    }
}

3. 다음과 같이 jvm 매개 변수를 구성합니다.

         -Xms512m
         -Xmx512m
         -XX:-UseGCOverheadLimit
         -XX:MaxPermSize=50m

4. 프로그램을 실행하고 visualvm 모니터링을 엽니 다.

JVisualVM은 Tomcat을 원격으로 모니터링합니다.

1. 원격 Tomcat의 catalina.sh 구성 파일을 수정하고 다음을 추가합니다.

  • JAVA_OPTS = "$ JAVA_OPTS
  • Djava.rmi.server.hostname = 192.168.122.128
  • Dcom.sun.management.jmxremote.port = 18999
  • Dcom.sun.management.jmxremote.ssl = false
  • Dcom.sun.management.jmxremote.authenticate = false "

이번에는 구성이 권한 확인을 거치지 않습니다. jmx 포트를여십시오.

2. jvisualvm을 열고 원격을 마우스 오른쪽 단추로 클릭 한 다음 원격 호스트 추가를 선택합니다.
여기에 사진 설명 삽입

3. 다음과 같이 호스트 이름을 입력하고 ip를 직접
여기에 사진 설명 삽입
작성합니다. 새로 생성 된 호스트를 마우스 오른쪽 버튼으로 클릭하고 Add JMX connection을 선택한 다음 tomcat에 구성된 포트를 입력합니다.

4. 두 번 클릭하여 엽니 다. 완전한!

JVisualVM을 사용하여 메모리 누수 분석

1. Visual GC 탭을 확인합니다. 내용은 다음과 같습니다. 이것은 먼저 출력의 스크린 샷입니다.
여기에 사진 설명 삽입
이것은 4의 출력의 스크린 샷 입니다 :
여기에 사진 설명 삽입
두 사진의 비교를 통해
여기에 사진 설명 삽입
여기에 사진 설명 삽입
구세대가 들어 왔음을 알 수 있습니다. gc. 프로그램이 계속 실행되면 구세대 gc가 여전히 계속되고 있음을 알 수 있습니다.
여기에 사진 설명 삽입
증가 7 배이지만 구세대의 메모리는 감소하지 않았습니다. 재활용 할 수없는 개체가 있음을 보여 주며 메모리 누수 일 수 있습니다.
물체가 유출되었는지 분석하는 방법은 무엇입니까? 샘플러 탭을 엽니 다. 아래 그림과 같이 클릭합니다.
여기에 사진 설명 삽입
프로그램의 출력을 따라 힙을 덤프하고, 두 번째로 출력 할 때, 한 번 덤프하고, 나중에 출력 할 때 한 번 덤프합니다.
마지막 덤프의 힙 레이블을 입력하고 카테고리를
여기에 사진 설명 삽입
클릭하십시오. 오른쪽 상단 모서리를 클릭하십시오 : "다른 힙 스토리지와 비교". 도면에 도시 된 바와 같이, 제 수출 덤프 콘텐츠 비교 선택 :
여기에 사진 설명 삽입
비교 결과는 다음과 같다 : 이는
여기에 사진 설명 삽입
TestMemory 객체 인스턴스에있어서, 상기에서 언급 된 것을 나타내는 증가보다 두 배의 간격으로되어있는 것을 알 수있다 개체에 메모리 누수가있을 수 있습니다.
개체 참조 관계를 보는 방법은 무엇입니까?
아래와 같이 TestMemory 클래스를 마우스 오른쪽 버튼으로 클릭하고 "인스턴스보기에 표시"를 선택합니다.
여기에 사진 설명 삽입
왼쪽은 생성 된 총 인스턴스 수, 오른쪽 상단은 인스턴스의 구조, 다음은 참조 설명입니다. CyclicDependencies 클래스의 그림에서 볼 수 있습니다. HashMap에서 참조하고 참조합니다.

이러한 방식으로 누출 위치를 파악한 다음 실제 상황에 따라 분석하고 해결할 수 있습니다.

JVM 튜닝을 수행하는 방법

메모리 해제, 컬렉션 클래스 검사, 개체 트리 관찰

위의 튜닝 도구는 모두 강력한 기능을 제공하지만 일반적으로 다음과 같은 기능 범주로 나뉩니다.

힙 정보보기

img

힙 공간 할당 (젊은 세대, 구세대, 영구 세대 할당)을 볼 수 있습니다.

즉각적인 가비지 수집 제공

쓰레기 모니터링 (장시간 재활용 상황 모니터링)

img

힙에서 클래스 및 객체 정보보기보기 : 수량, 유형 등

img

개체 참조보기

힙 정보보기 기능을 사용하면 일반적으로 다음 문제를 원활하게 해결할 수 있습니다.

-노년층과 젊은 세대의 크기 구분이 합리적입니까?

-메모리 누수

-가비지 수집 알고리즘 설정이 합리적인지 여부

스레드 모니터링

img

스레드 정보 모니터링 : 시스템 스레드 수.

스레드 상태 모니터링 : 각 스레드의 상태

img

스레드 세부 사항 덤프 : 스레드의 내부 작업보기

교착 상태 확인

핫스팟 분석

img

Hot CPU : CPU 시간이 많이 걸리는 시스템 확인

메모리 핫스팟 : 시스템에서 어떤 개체 (개체가 특정 시간 통계에서 생존하고 개체를 함께 파괴)하는지 확인하는 최대 수

이 두 가지는 시스템 최적화에 매우 유용합니다. 시스템의 병목 현상을 검색하고 모든 코드를 목적없이 최적화하는 대신 발견 된 핫스팟을 기반으로 목표 방식으로 시스템을 최적화 할 수 있습니다.

스냅 사진

스냅 샷은 특정 순간까지 실행되는 시스템의 고정 프레임입니다. 튜닝 할 때 눈으로 모든 시스템 변경 사항을 추적하는 것은 불가능합니다. 스냅 샷 기능에 의존하면 시스템의 두 가지 다른 런타임에서 순서대로 객체 (또는 클래스, 스레드 등) 간의 차이를 만들 수 있습니다. 문제를 빨리 찾기 위해

예를 들어, 시스템이 가비지 수집 된 후 복구해야 할 개체가 누락되었는지 확인하고 싶습니다. 그런 다음 가비지 수집 전후의 힙 상황에 대한 스냅 샷을 찍고 두 스냅 샷의 객체 상황을 비교할 수 있습니다.

메모리 누수 검사

메모리 누수는 비교적 일반적인 문제이며 해결 방법도 비교적 일반적인데 여기서 집중할 수있는 반면 스레드 및 핫 이슈는 세부적으로 분석되는 특정 문제입니다.

메모리 누수는 일반적으로 잘못된 사용의 경우 시스템 리소스 (모든 측면의 리소스, 힙, 스택, 스레드 등)로 이해 될 수 있으며, 그 결과 사용 된 리소스를 재활용 (또는 재활용하지 않음) 할 수 없어 새로운 리소스가 생성됩니다. 할당 요청을 완료 할 수 없습니다. 시스템 오류가 발생합니다.

메모리 누수는 시스템에 직접적으로 충돌을 일으킬 수 있기 때문에 시스템에 더 해 롭습니다.

구별 할 필요가 있지만 최종 결과는 동일 할 수 있지만 메모리 누수와 시스템 과부하 사이에는 차이가 있습니다. 메모리 누수는 사용 된 리소스가 복구되지 않고 오류를 발생시키는 반면 시스템 과부하는 시스템에 할당 할 리소스가 너무 많지 않다는 것입니다 (다른 리소스가 사용 중임).

이전 세대 힙 공간이 가득 찼습니다.

참고 : java.lang.OutOfMemoryError : Java 힙 공간

기술:

img

가장 일반적인 메모리 누수 방법입니다. 간단히 말해서 모든 힙 공간은 재활용 할 수없는 가비지 개체로 채워지고 가상 머신은 더 이상 새 공간을 할당 할 수 없습니다.

위의 그림에서 볼 수 있듯이 이것은 메모리 누수의 매우 일반적인 가비지 수집 그림입니다. 모든 피크 부분은 가비지 수집 지점이고 모든 아래쪽 부분은 가비지 수집 후 남은 메모리를 나타냅니다. 모든 계곡 지점을 연결하면 아래에서 위로 선을 찾을 수 있습니다. 이는 시간이 지남에 따라 시스템의 힙 공간이 지속적으로 점유되고 결국 전체 힙 공간이 점유된다는 것을 보여줍니다. 따라서 시스템에 메모리 누수가있을 수 있음을 미리 고려할 수 있습니다. (위 사진은 예시 일뿐, 실제 상황에서는 몇 시간 또는 며칠 등 데이터 수집 시간이 더 오래 걸립니다.)

풀다:

이 방법도 비교적 쉽게 해결할 수 있으며, 일반적으로 가비지 콜렉션 전후 ​​상황을 비교하고 객체 참조 상황 (공통 콜렉션 객체 참조)을 기반으로 분석하여 기본적으로 누수를 찾을 수 있습니다.

지속적인 세대가 차지하고 있습니다.

** 异常 : ** java.lang.OutOfMemoryError : PermGen 공간

기술:

파마 공간이 점유되었습니다. 새 클래스에 대한 스토리지 공간을 할당 할 수 없기 때문에 발생하는 예외입니다. 이 예외는 이전에 존재하지 않았지만 오늘날 Java 리플렉션이 많이 사용되는 경우 더 일반적입니다. 주된 이유는 동적 반사에 의해 생성 된 많은 수의 클래스가 지속적으로로드되어 결국 Perm 영역이 가득 차게하기 때문입니다.

더 무서운 것은 다른 classLoader가 동일한 클래스를 사용하더라도 모두로드한다는 것인데, 이는 동일한 것과 동일하며 N 개의 classLoader가 있으면 N 번로드됩니다. 따라서 경우에 따라이 문제는 기본적으로 해결할 수없는 것으로 간주됩니다. 물론 많은 수의 classLoader와 많은 수의 리플렉션 클래스가있는 경우는 많지 않습니다.

풀다:

  1. -XX : MaxPermSize = 16m

  2. JDK로 전환하십시오. JRocket과 같은.

스택 오버플로

** 예외 : ** java.lang.StackOverflowError

** 참고 : ** 이에 대해 많이 말하지 않겠습니다. 일반적으로 반환되지 않는 재귀 또는 순환 호출로 인해 발생합니다.

스레드 스택 가득 참

异常: 치명적 : 스택 크기가 너무 작음

참고 : Java에서 스레드의 공간 크기는 제한되어 있습니다. JDK5.0 이후이 값은 1M입니다. 이 스레드와 관련된 데이터가 여기에 저장됩니다. 그러나 스레드 공간이 가득 차면 위의 예외가 발생합니다.

솔루션 : 스레드 스택 크기를 늘리십시오. -Xss2m. 그러나이 구성은 근본적인 문제를 해결할 수 없으며 코드 부분에 누수가 있는지 여부에 따라 다릅니다.

시스템 메모리가 가득 찼습니다

异常: java.lang.OutOfMemoryError : 새 원시 스레드를 만들 수 없습니다.

설명 :

이 예외는 운영 체제에이 스레드를 생성하기에 충분한 리소스가 없기 때문에 발생합니다. 시스템이 스레드를 생성 할 때 Java 힙에 메모리를 할당하는 것 외에도 운영 체제 자체도 스레드를 생성하기 위해 리소스를 할당해야합니다. 따라서 스레드 수가 일정 수준에 도달하면 힙에 공간이있을 수 있지만 운영 체제에서 리소스를 할당 할 수 없어이 예외가 발생합니다.

JVM (Java Virtual Machine)에 할당 된 메모리가 많을수록 시스템에 남아있는 자원이 적어집니다. 따라서 시스템 메모리가 고정 된 경우 Java 가상 머신에 할당되는 메모리가 많을수록 시스템에서 생성 할 수있는 스레드 수가 줄어 듭니다. 관계는 반비례합니다. . 동시에 -Xss를 수정하여 단일 스레드에 할당 된 공간을 줄일 수 있으며 시스템에서 생성되는 총 스레드 수를 늘릴 수도 있습니다.

풀다:

  1. 스레드 수를 줄이기 위해 시스템을 재 설계하십시오.

  2. 스레드 수를 줄일 수없는 경우 -Xss를 사용하여 단일 스레드의 크기를 줄이십시오. 더 많은 스레드를 생산할 수 있습니다.

JVM 매개 변수 최적화 제안

기본적으로 GC 수를 줄입니다.

객체를 자주 생성하는 어플리케이션이라면 적절하게 젊은 세대의 크기를 늘릴 수 있습니다. 더 많은 상수는 지속적 생성 크기를 증가시킬 수 있습니다. 싱글 톤이 더 많은 객체의 경우 이전 세대의 크기를 늘릴 수 있습니다. 예를 들어, 봄 응용 프로그램에서.

GC 선택, JDK5.0 이후 JVM은 현재 시스템 구성 에 따라 판단 합니다 . 일반적으로 -Server 명령을 실행합니다. gc에는 직렬, 병렬 및 동시의 세 가지 전략이 있습니다.

처리량이 크게 적용되며 일반적으로 병렬 수집을 사용하며 gc의 속도를 높이기 위해 다중 스레드를 사용합니다.

응답 속도가 빠른 응용 프로그램은 일반적으로 응용 프로그램 서버와 같은 동시 수집을 사용합니다.

이전 세대는 동시 수집기로 구성하는 것이 좋습니다. 동시 수집기는 디스크를 압축하고 조각 모음하지 않으므로 다음을 구성하는 것이 좋습니다.

-XX : + UseConcMarkSweepGC # 구세대 동시 수집

-XX : CMSInitiatingOccupancyFraction = 80 # 이전 세대 공간이 80 %에 도달하면 CMS가 실행됨을 나타냅니다.

-XX : + UseCMSCompactAtFullCollection # 이전 세대의 압축을 켭니다. 성능에 영향을 미칠 수 있지만 메모리 조각화를 제거 할 수 있습니다.

-XX : CMSFullGCsBeforeCompaction = 10 # 동시 수집기는 메모리 공간을 압축하고 구성하지 않으므로 일정 시간 실행 후 "조각"을 생성하여 운영 효율성을 떨어 뜨립니다. 이 매개 변수는 FullGC를 실행 한 후 메모리 공간을 압축하고 구성하도록 설정됩니다.

추천

출처blog.csdn.net/crazymakercircle/article/details/113758988