JVM의 심층 이해 (2 개) JVM 메모리 모델

원본 링크 : http://www.cnblogs.com/xuyuanpeng/p/11098601.html

I. 서론

가상 머신에 메모리에 대해 이야기보다도, 즉, 우리는 스레드에 메모리를 공유하고 개인 스레드.
스레드에 의해 공유되는 Java 힙 및 방법 영역입니다. 자바 힙은 우리가 익숙하지있을 수 있습니다, 그리고 메소드 영역 그는 또한 영구적 인 세대로 알려져, 일정한 수영장이 포함되어 있습니다. 이 방법은 일반적으로 영역도 아닌 힙 될 것이라고하지만, 논리적으로, 그는 자바 힙의 일부이며, 직접적으로 어떤 가상 메소드 합병 기회 자바 힙.
개인 가상 머신 스택되어 스레드 가상 머신 스택, 네이티브 메소드 스택 및 프로그램 카운터 동안. 여기에서 우리는 논의하지 않습니다.
나는 잠시, 가상 머신의 위의 메모리 파티션을 검토 다음 텍스트를 시작합니다.

두, 자바 메모리 모델 설명

1 주 메모리

자바 메모리 모델은 모든 변수가 그들의 메인 메모리에 저장되어야 함을 지정합니다.

2, 작업 메모리

매일 그 작업 메모리를 개인 메모리 스레드.
메모리를 작업에 사용되는 스레드의 메인 메모리 변수의 사본의 사본을 저장합니다. 당신이 스레드를 무슨 짓 변수는 작업 기억에 있어야합니다.
다른 스레드는 스레드 작업 메모리, 메인 메모리, 세 사이의 정보 교환을 달성하기 위해 단지 주 메모리를 통해 서로 작동 변수 메모리에 액세스 할 수있다.
: 다이어그램은 다음과
여기에 그림 삽입 설명
메인 메모리, 작업 기억, 그리고 자바 힙 메모리 영역에 대한 내 마지막 블로그, 영역과 다른 방법을 스택, 메모리 부문의 동일한 수준이 아니다.
다른 쉬운 우리가 이해할 수 기억 :
메인 메모리는 데이터 부분은, Java 힙에 대응하는 부분 영역에 대응하는 작업용 메모리의 일례이다 Java 가상 머신 스택이다.
컴퓨터 조직의 원칙에서, 그래서 우리는 메인 메모리 및 프로세스 데이터 교환, 그것은 매우 시간이 많이 걸리는 것, 그래서 만약 메인 메모리는 물리적 하드웨어 메모리에 해당하고, 이해 될 수있다.
프로그램이 일반 액세스 작업 메모리를 실행하기 때문에, 레지스터와 캐시에 저장된 메모리 우선 순위 작업.
(부 블로그의 시작 부분, 즉, 조직 원리의 측면에서 따로 운영 체제 및 가상 머신을 넣어 대해 왕따에게 = _ =)

셋째, 원자 회상에

코드 부분부터 1

어떤 BB, 쇼 코드 없습니다

    private static volatile  int i = 0;
    public static  void add(){
        i++;
    }

    public static void main(String [] args){

        for(int c=0; c<20; c++){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int k = 0; k<10000; k++){
                        add();
                    }
                }
            });
            thread.start();
        }
        while (Thread.activeCount()>1){
            Thread.yield();
        }
        System.out.println(i);
    }

위의 코드를 읽는다면, 당신은 위의 코드 본적이 없다면, 읽기 계속에서 생각하고 여기에 제안 할 수 있습니다, 최종 출력 값은 얼마입니까?
물론, 결과는 20 만은 아니다. (최종 결과가 20이라면, 내가 왜 =이 예제를 제공 않습니다. =)

2, 가상 기계 운영 원자 안쪽

그들의 장로, 또는 다른 사람의 제안이 이미 언급 한 여부, 효율성을 읽기에 문제가 정처없이, 훨씬 더 나은 결과보다 읽을 수 있습니다, 그래서 위의 문제를 제기, 다음은 토론의 자연 양의 문제를 해결하고 확장하기 위해서입니다 지침. 여기에, 자바 가상 머신의 메모리 동작의 시작과 함께 시작합니다.

잠금 : 메인 메모리의 역할이 변수 플래그의 메인 메모리는 전용 스레드입니다.
해제 : 메인 메모리에 작용, 로킹 상태로부터 자유롭게 주기억 변수, 가변 해방 다른 스레드에 재 점유 할 수있다.
읽어 메인 메모리에 작용, 작업 메모리에 주기억으로부터 송신 주기억 변수.
부하 : 작업 기억의 역할, 값을 읽을 수 있습니다, 그들의 작업 메모리의 사본을 넣어.
사용 : 작업 메모리의 역할, 실행 엔진에 전달되는 변수의 작업 메모리를. 바이트 코드의 설명은 가상 머신에 의해 실행될 때,이 값을 이용하면,이 동작을 수행한다.
할당 : 작업 메모리의 역할을 실행 엔진의 값은 작업 메모리 변수에 할당 받았다. 때마다 할당 문 바이트 코드의 실행이 작업을 사용합니다.
저장소 : 작업 메모리에 변수 작용, 작업 메모리에서 변수, 메인 메모리에 전송.
작성 : 주 메모리에 작용 저장소가 메인 메모리에 변수 변수 작업 메모리로부터 취득.

3 분할 원자의 작동

아토믹 조작 판독,로드를 사용하여, 일반적으로 두 부분으로 분할 된 데이터의 자성을 보장 할 수있는 등, 읽기 및 쓰기 작업 물품.
그러나 때때로 우리는 당신이 잠금을 사용하여 잠금을 해제 할 필요가 원 자성을 가지고, 전체 비즈니스 코드가 필요합니다.

4, 휘발성 설명

엄수 학생들은 위의 내 코드를 발견 할 수 있습니다. 그것은 탐색하는 동안 휘발성 선언된다.
그래서 휘발성의 역할은 무엇인가?
일반적으로, 모든 스레드의 휘발성 변수는 볼 수 이해합니다. 모든 쓰기 휘발성 변수의 경우, 다른 스레드에 대한 반응을 이해할 수있다.
즉, 휘발성 때문에 동시 휘발성 변수에 기반으로 모든 작업이 안전, 모든 스레드에서 일치한다.
실제 사실, 휘발성 변수 및 보안 동시성을 보장 할 수 없습니다.

(1) 비교 결과
변수 유형 1의 결과 실행 결과 2 3의 결과 4의 결과 5의 결과 평균 값 (극값 제거)
휘발성 물질 186632 196403 193658 197305 186825 192295
일반 변수 178387 179369 189835 174015 199458 182530

나는 다섯 개 코드의 결과를 기록했다. 표에 나타낸 바와 같이. 아니 목표 20 만. 그것은 그 휘발성 변수가 선언되지 및 선언되지, 정확히 동일합니다?
확실히, 나는 휘발성 문을 제거 한 후, 실행 결과는 표에서 볼 수 있듯이, 얻을.
마지막으로 우리는 휘발성 문의 또한이 결과는 목표 값에 더 가까운 결론을 내렸다. 그것은 이러한 현상이란의 원인은?

(2) 바이트 코드 명령어부터 시작

보기 바이트 코드는 일반적으로 두 가지 방법이 있습니다.
첫째, 생산 클래스 파일을 찾을 수 컴파일 된 코드를 참조 지침은 javap 실행합니다.
당신이 (세계에서 최고의 아이디어) 아이디어 편집기를 사용하는 경우 둘째, 당신은 당신이보고 싶은 자바 클래스를 선택할 수 있습니다,보기 메뉴가 표시 바이트 코드를 클릭합니다.
두 가지 방법으로, 나는 보통이 두 가지 편리한 방법을 선택하고, 내 독서 습관에 맞춰 코드 형식을 볼 수있는 방법입니다.

 public static void add();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #2                  // Field i:I
         3: iconst_1
         4: iadd
         5: putstatic     #2                  // Field i:I
         8: return
      LineNumberTable:
        line 12: 0
        line 13: 8
바이트 코드 지침 휘발성 선언 객체의 실행 과정 설명

그는 메인 메모리의 변화 값 때 참으로, 즉시 작업 기억에 반응하는 것, 휘발성 변수 선언 객체.
다음은 노드가있다, 즉, 우리는 바이트 코드

getstatic

최신 실시간 변수 값을 얻는 것이다 getstatic 지시자. 이 값이 +1하고 반환 이후. 그러나,이 값에 +1 또는 복귀 동작, 다른 스레드가 처리 될 때, 스레드의 반환 값을 초래하는 정확한 값이 아니라고 경우가있다.
아직 우리가 어떤 장면 시뮬레이션, 이해하지 않을 수 있습니다.

  • ① 장면의
    시간을 1 : 1이 값을 획득 쓰레드. (빠른)
    2 시간 : 스레드 B는 1의 값을 획득한다. (빠른 시간)
    (3)의 시간 (느린)이 값 C (1)을 얻었다 스레드
  • ② 장면
    시간 포인트 (4) : 스레드가 그 값을 처리하는 값을 완료하고, 메인 메모리에 기록되고, 상기 메모리는 황제 2. 완료된
    순간 5 : B 스레드, 메인 메모리 내의 스레드 A가 완료의 값을 수정하기 만 getstatic 시작 명령, 그 마지막 2 + 1, 배면 메인 메모리 (3) 마무리를 실행하고
    , 스레드 A는 메인 메모리에 데이터를 기록 끝난 실행 C 스레드 getstatic 방법 및 B는 여전히 +1 수행 쓰레드 시간 6 . 이 경우 메인 메모리 (2)이다. 그는 다시 2 +1 운영, 메인 메모리 (3) 구현이 기록 된 후에.
    그래서 결국 메인 메모리 (4)은 목표 아닌, 3입니다. 이것은 우리의 코드 실행 결과이며, 그 이유는보다 20 만입니다.
휘발성 선언 과정을 설명 객체 바이트 코드없이

전에 휘발성 선언하지 않고, getstatic 명령하지 않을 수 있습니다 스레드를 입력 한 후, 변수 값이 변경하지만, 스레드 모르겠어요.
그래서,이 플러스입니다

넷째, 올바른 자세는 스레드 안전

이 이야기에서, 나는 우리가 위의 코드의 구현의 결과에 대한 아무 의심을 가진다한다고 생각합니다.
그러나 문제는 다시, 어떻게 올바른 대상을 얻을 수 있음을 확인합니다.

도 1에서, 동기 전능

우리는이 키워드를 참조 비교, 당신은 이미 내가 다음 말을 원하는 것을 알고있다.

 public synchronized static  void add(){
        i++;
    }

대상 결과는 add 메소드를 들어, 20,000의 목표입니다, 마지막으로 얻을 이후에 수정 동기화 된 키워드를 추가 할 수 있습니다.
물론, 더 보편적 종종 더 무능을 나타냅니다.
이 방법의 성능은 훨씬 더의 성능을 자신의 손을 사용하는 것보다 고정하고 잠금을 해제하는 것입니다.
특히 JDK 버전 1.5, 성능 차이는 매우 크다. 그러나 이후의 JDK 버전에서의 최적화 동안 점진적으로 동기화. 그는 우아하고, coooooool 많은 수 ReentrantLock와보다 그리고 정부는 결국,이 방법을 권장하고있다.

2, 고성능 ReentrantLock와

private static  int i = 0;
    private static ReentrantLock lock = new ReentrantLock();
    
    public  static  void add(){
        lock.lock();
        try{
            i++;
        }finally {
            lock.unlock();
        }
    }

심지어 우리가 시도해야, ++, 이것은 좋은 습관 의미 = _ = 개발하는 것입니다
잠금 해제 될 수밖에 모든 잠금을. 이봐, 그렇지 않으면 .... 어이
그것은 주목해야한다 인터럽트 공정 잠금을 달성하기위한 여러 조건을 결합 할 수로, ReentrantLock와 (재진입 잠금) 동기화 된 이상은, 기타 고급 기능보다 더 많은, 기다립니다. 다음은 토론을 수행 할 수 없습니다.

(3) 좁은 AtomicInteger

 private static AtomicInteger i =new AtomicInteger(0);
    public  static  void add(){
        i.addAndGet(1);
    }

원자 객체는 등등 AtomicBoolean, AtomicLong과 같이 많은입니다.
그는 원칙의 실현은 CAS에 의해 원칙, 원자 데이터 작업을 안심하시기 바랍니다.
CAS는 무엇입니까? 즉, 비교 및 교환 :
주기억 값 (A)을 획득 매개로 새로운 값 (B)을 취득한 값 (A). 여기서 그 값은 값이 얻어지는 송신 값 (A)과 일치하는 경우, 주기억 B.의 새로운 값의 값을 수정하기 위해, 수득
이는 CAS의 인
에 Atimic를 달성 물론, 또는 안전하지 않은 클래스를 사용, 그는 직접 실제 메모리를 조작 할 수 있습니다! ! ! !
여기에서 우리는 그의 정확한 시작되지 않습니다.

V. 요약

메모리 모델은 메인 메모리와 메모리 작업으로 구분.
사실, 나는 왜 작업 메모리와 메인 메모리 사이를 구별해야 그것을 다른 방법을 너무 의미 넣어 말? ?
스레드 프로그램에 기초하여 실행되고 있으며, 스레드는 컴퓨터와 데이터를 교환 할 필요가 있지만 인하여 컴퓨터의 구성에, 데이터 교환은 일부 메모리 영역 전송 속도 약간 느린 전송 될 것이다. 또한 우리는 (물리적 메모리로 좁게 이해 될 것이다) 및 작업 메모리, 메인 메모리를 구별, 데이터의 보안을 보장하는 (즉, 캐시 레지스터 시간은, 또한 실제 메모리에 저장된 경우)

JVM 다시 방문 할 때, 여러 번 그 이유를 생각? 그 이유는 이러한 설계, 그래서 뭐 좋은 디자인, 수익의 많은입니다.

여섯 번째로, 레퍼런스

"자바 가상 머신에 대한 심층 이해"

HTTPS : //www.cnblogs.com/xuyuanpeng/p/11098601.html 재현

추천

출처blog.csdn.net/weixin_30612769/article/details/94953405