CodeGym/Java курс/Модул 3/Памет в JVM, част 2

Памет в JVM, част 2

На разположение

Хардуерна архитектура на паметта

Съвременната хардуерна архитектура на паметта се различава от модела на вътрешна памет на Java. Следователно трябва да разберете хардуерната архитектура, за да знаете How моделът на Java работи с нея. Този раздел описва общата хардуерна архитектура на паметта, а следващият раздел описва How Java работи с нея.

Ето опростена диаграма на хардуерната архитектура на модерен компютър:

Хардуерна архитектура на паметта

В съвременния свят компютърът има 2 or повече процесора и това вече е норма. Някои от тези процесори може също да имат няколко ядра. На такива компютри е възможно да се изпълняват няколко нишки едновременно. Всяко процесорно ядро ​​може да изпълни една нишка във всеки даден момент. Това означава, че всяко приложение на Java е априори многонишково и във вашата програма може да работи по една нишка на процесорно ядро ​​в даден момент.

Ядрото на процесора съдържа набор от регистри, които се намират в неговата памет (вътре в ядрото). Той извършва операции с регистърни данни много по-бързо, отколкото с данни, които се намират в основната памет на компютъра (RAM). Това е така, защото процесорът има достъп до тези регистри много по-бързо.

Всеки CPU може също да има свой собствен кеш слой. Повечето съвременни процесори го имат. Процесорът има достъп до кеша си много по-бързо от основната памет, но не толкова бързо, колкото вътрешните му регистри. Стойността на скоростта на достъп до кеша е приблизително между скоростите на достъп на основната памет и вътрешните регистри.

Освен това процесорите имат къде да имат многостепенен кеш. Но това не е толкова важно да се знае, за да се разбере How моделът на паметта на Java взаимодейства с хардуерната памет. Важно е да знаете, че процесорите може да имат известно ниво на кеш памет.

Всеки компютър също съдържа RAM (област на основната памет) по същия начин. Всички ядра имат достъп до основната памет. Областта на основната памет обикновено е много по-голяма от кеш паметта на процесорните ядра.

В момента, в който процесорът се нуждае от достъп до основната памет, той чете част от нея в своята кеш памет. Той може също да чете някои данни от кеша във вътрешните си регистри и след това да извършва операции с тях. Когато процесорът трябва да запише резултата обратно в основната памет, той ще изчисти данните от своя вътрешен регистър в кеша и в даден момент в основната памет.

Данните, съхранявани в кеша, обикновено се изхвърлят обратно в основната памет, когато процесорът трябва да съхрани нещо друго в кеша. Кешът има възможност да изчиства паметта си и да записва данни едновременно. Процесорът не трябва да чете or записва пълния кеш всеки път по време на актуализация. Обикновено кешът се актуализира в малки блокове памет, те се наричат ​​"кеш линия". Един or повече "кеш редове" могат да бъдат прочетени в кеш паметта и един or повече кеш редове могат да бъдат изчистени обратно в основната памет.

Комбиниране на модел памет на Java и хардуерна архитектура на паметта

Както вече споменахме, моделът на паметта на Java и хардуерната архитектура на паметта са различни. Хардуерната архитектура не прави разлика между стекове от нишки и купчини. На хардуера стекът от нишки и HEAP (купчина) се намират в основната памет.

Части от стекове и купчини от нишки понякога могат да присъстват в кеш паметта и вътрешните регистри на процесора. Това е показано на диаграмата:

стек от нишки и HEAP

Когато обекти и променливи могат да се съхраняват в различни области на паметта на компютъра, могат да възникнат определени проблеми. Ето двата основни:

  • Видимост на промените, които нишката е направила в споделените променливи.
  • Състезание при четене, проверка и запис на споделени променливи.

И двата въпроса ще бъдат обяснени по-долу.

Видимост на споделените обекти

Ако две or повече нишки споделят обект без правилно използване на непостоянна декларация or синхронизация, тогава промените в споделения обект, напequalsи от една нишка, може да не са видими за други нишки.

Представете си, че споделен обект първоначално се съхранява в основната памет. Нишка, изпълнявана на CPU, чете споделения обект в кеша на същия CPU. Там той прави промени в обекта. Докато кешът на процесора не бъде изчистен в основната памет, модифицираната version на споделения обект не е видима за нишки, работещи на други процесори. По този начин всяка нишка може да получи собствено копие на споделения обект, всяко копие ще бъде в отделен кеш на процесора.

Следващата диаграма илюстрира схематично тази ситуация. Една нишка, работеща на левия CPU, копира споделения обект в своя кеш и променя стойността на count на 2. Тази промяна е невидима за други нишки, изпълнявани на десния CPU, тъй като актуализацията за count все още не е върната обратно в основната памет.

За да разрешите този проблем, можете да използвате ключовата дума volatile, когато декларирате променлива. Той може да гарантира, че дадена променлива се чете директно от основната памет и винаги се записва обратно в основната памет, когато се актуализира.

Състояние на състезанието

Ако две or повече нишки споделят един и същ обект и повече от една нишка актуализира променливи в този споделен обект, тогава може да възникне състояние на състезание.

Представете си, че поток A чете променливата за броя на споделения обект в кеша на своя процесор. Представете си също, че нишката B прави същото, но в кеша на друг процесор. Сега нишка A добавя 1 към стойността на count, а нишка B прави същото. Сега променливата е увеличена два пъти - отделно с +1 в кеша на всеки процесор.

Ако тези увеличения бяха извършени последователно, променливата за броене ще бъде удвоена и записана обратно в основната памет (първоначална стойност + 2).

Две стъпки обаче бяха извършени едновременно без подходяща синхронизация. Независимо коя нишка (A or B) записва своята актуализирана version на броя в основната памет, новата стойност ще бъде само с 1 повече от първоначалната стойност, въпреки двете увеличения.

Тази диаграма илюстрира възникването на проблема със състоянието на състезание, описан по-горе:

За да разрешите този проблем, можете да използвате Java synchronized block. Синхронизираният блок гарантира, че само една нишка може да влезе в даден критичен раздел от code във всеки даден момент.

Синхронизираните блокове също така гарантират, че всички променливи, достъпни вътре в синхронизирания блок, ще бъдат прочетени от основната памет и когато нишката излезе от синхронизирания блок, всички актуализирани променливи ще бъдат върнати обратно в основната памет, независимо дали променливата е обявена за летлива or не.

Коментари
  • Популярен
  • Нов
  • Стар
Трябва да сте влезли, за да оставите коментар
Тази страница все още няма коментари