2017-12-25 46 views
0

Java 메모리 모델을 이해하려고하지만 CPU 캐시와 관련하여 문제가 발생하지 않았습니다.공유 변수가 CPU 캐시에 캐시되는 이유는 무엇입니까?

지금까지 내가 JVM에서 우리가 로컬 및 공유 변수에 저장하려면 다음 위치가, 그것을 알고 :

local variables -- on thread stack 

shared variables -- in memory, but every CPU cache has a copy of it 

그래서 내 질문은을 왜 저장 지역 스택에 변수, (캐시) 공유 변수 CPU 캐시에? 다른 방법으로 (CPU 캐시가 둘 다 저장하기에는 너무 비싸다고 가정하면) CPU 캐시에 로컬 변수를 캐시하고 메모리에서 공유 변수를 가져 오는 것입니까? 이 부분이 Java 언어 디자인 또는 컴퓨터 아키텍처의 일부입니까?

"CPU 캐시"소리처럼 간단하게 여러 CPU가 하나의 캐시를 공유한다면 어떻게 될까요? 그리고 다중 레벨 캐시를 가진 시스템에서, 공유 레벨의 사본은 어느 레벨의 캐시에 저장 될까요? 또한 동일한 CPU 코어에서 두 개 이상의 스레드가 실행중인 경우 동일한 캐시 된 공유 변수 집합을 공유한다는 의미이며 따라서 공유 변수가 정의되지 않은 경우에도 변수의 액세스는 즉시 즉시 가능합니다 동일한 CPU에서 실행중인 다른 스레드에 표시됩니까?

+0

원시 타입이 아닌 경우, * "변수 값"*은 Java의 * references-to * 객체 일뿐입니다. * 객체 자체는 스택에 없습니다. 필드는 항상 객체 *와 연관되어 * 객체 *가 스택에 없으므로 * Java 메모리 모델은 필드 읽기/쓰기와의 관계에 다소 관대합니다. 스레드 가시성 문제가 자주 발생합니다 . – user2864740

+0

주제가 SO 질문에 비해 너무 광범위하고 불특정이지만 몇 가지 잘못된 가정이 있습니다. "로컬 변수 - 스레드 스택": 개념적 Java 아키텍처로 코드가 실제로 CPU에서 실행되는 방식과 거의 관련이 없습니다. 그러나 대부분의 경우 메인 메모리에 저장되고 CPU 캐시에 캐싱 될 수 있습니다. 다른 스레드와 공유되지 않습니다. "공유 변수 - 메모리에 있지만 모든 CPU 캐시에는 복사본이 있습니다"- 아니요, CPU 캐시는 그다지 크지 않습니다. 해당 CPU가 해당 데이터를 사용할 때만 데이터를로드합니다. –

답변

1

"로컬"변수와 "공유"변수는 코드 컨텍스트 외부에서 의미가 없습니다. 상태가 캐시되는 위치 또는 영향을받지 않습니다. 국가가 어디에 저장되어 있는지 생각하거나 추론하는 것은 유용하지 않습니다. JMM이 존재하는 모든 이유는 아키텍처와 아키텍처에 따라 달라지는 이러한 세부 사항이 프로그래머에게 노출되지 않도록하기 위해서입니다. 저수준 하드웨어 세부 사항에 의존함으로써 JMM에 대한 잘못된 질문을하고 있습니다. 응용 프로그램에 유용하지 않으며, 깨지기 쉽고, 깨지기 쉽고, 추론하기가 어려우며, 이식성이 떨어집니다.

그렇다면 일반적으로 모든 상태가 아닌 모든 프로그램 상태가 캐시 될 수 있다고 가정해야합니다. 실제로 캐시 된 것은 실제로 중요하지 않으며, 기본 유형이든 참조 유형이든 또는 여러 필드로 캡슐화 된 상태 변수 일지라도 모든 것이 될 수 있습니다. 스레드가 실행하는 명령어가 무엇이든간에 (아키텍처에 따라 그 명령어가 다르다 조심하십시오!), 명령어는 CPU와 관련하여 캐시와 관련된 내용과 캐시하지 않을 내용을 다시 지정합니다. 프로그래머가 스스로 이것을 할 수는 없습니다 (은 입니다. 영향, 상태 변수가 캐시 될 수 있습니다, false sharing 참조).

다시 말하지만, 우리는 또한 활성 기본 유형은 P/ALU가 가장 빠른 그들과 함께 작업 할 수 있기 때문에 아마 레지스터에 넣어 것으로, 86에 대해 좀 더 일반화 할 수 있습니다. 다른 것은 그나저 간다. 코어 - 로컬 인 경우 프리 머 티브를 L1/2 캐시로 옮길 수 있습니다. 확실히 덮어 쓰기가 가능합니다. CPU는 장래 컨텍스트 스위치가있을 것이라고 생각하면 공유 L3에 상태 변수를 넣을 수 있습니다. 하드웨어 전문가가 이에 대응해야합니다.

이상적으로 상태 변수는 가장 가까운 캐시 (레지스터, L1/2/3, 메인 메모리)에 프로세서 장치에 저장하는 것이 이상적입니다. 그것은 CPU를 결정하는 것입니다. Java 레벨에서 캐시 시맨틱에 대한 이유는 불가능합니다. 비록 하이퍼 스레딩이 가능하다 할지라도 (나는 AMD가 무엇인지는 모르겠다.), 쓰레드는 리소스를 공유 할 수 없으며, 그렇다고하더라도 공유 상태 변수와 관련된 유일한 문제는 가시성이 아니라는 점을 기억해야한다. 프로세서가 파이프 라이닝을 수행하는 경우 올바른 순서 (이 경우에도 CPU에서 읽기/쓰기 버퍼링을 제거한 후에도)가 올바른지 확인하려면 적절한 지침이 필요합니다 (hwsync 또는 적절한 울타리인지 여부).

캐시의 속성에 대한 추론은 유용하지 않습니다. JMM이 캐시를 처리 할 수 ​​없기 때문에 캐시가 처리되지 않기 때문에 을 처리하기 때문입니다. 또한 어디/언제/어떤 질문을 알고 있더라도 STILL은 데이터 가시성에 대해 판단 할 수 없습니다. 모든 캐시는 어쨌든 캐시 된 데이터를 처리하므로 ME (O) SI 상태, 명령어 순서,로드/저장 버퍼링, 다시 쓰 기/통과 등의 캐시 상태를 업데이트하는 프로세서에 의존해야합니다. 여전히 OS 및 JVM 수준에서 발생할 수있는 문제는 아직 다루지 않았습니다. 다행히도 JDK에서는 volatile, final과 같은 기본 도구를 사용할 수 있으며 모든 플랫폼에서 일관되게 작동하는 원자와 예측 가능하고 쉬운 (쉽게) 코드를 생성 할 수 있습니다.

+0

당신은 내 모든 질문에 답하고 그림을 아주 분명하게했습니다. 가장 중요한 것은 _caching_이 _CPU scope_ 메커니즘에 더 가깝고 JVM 디자인과 아무 관련이 없다는 것을 이해하는 것입니다. Java 코드가 실행될 때 JVM 스레드 스택이 CPU와 어떻게 관련되는지는 분명하지 않습니다. 그러나 나는 그것이 대답하기에는 너무 광범위하다는 또 다른 질문이라고 생각한다. 매우 감사합니다. – justgivememyicecream