Utilizarea fișierelor pentru IPC cu memorie partajată, este o cerință maparea memoriei?

voturi
0

Există câteva proiecte care folosesc MappedByteBuffers returnate de FileChannel.map Java () ca o modalitate de a partaja IPC de memorie între JVM-uri pe aceeași gazdă (vezi Chronicle Queue, Aeron IPC, etc.). Din câte îmi dau seama, această aplicație este doar în partea superioară a apelului mmap. Cu toate acestea, implementarea Java nu permite mapări anonime (fără fișier cu suport).

Întrebarea mea este: pe Java (1.8) și Linux (3.10), sunt MappedByteBuffers într-adevăr necesare pentru implementarea IPC-ului cu memorie partajată, sau ar avea acces la un fișier comun aceeași funcționalitate? (Această întrebare nu se referă la implicația de performanță a utilizării unui MappedByteBuffer sau nu.)

Iată înțelegerea mea:

  1. Când Linux încarcă un fișier de pe disc, acesta copiază conținutul acelui fișier pe pagini din memorie. Acea regiune de memorie este numită memoria cache a paginii. Din câte îmi dau seama, face acest lucru indiferent de metoda Java (FileInputStream.read (), RandomAccessFile.read (), FileChannel.read (), FileChannel.map ()) sau metoda nativă este utilizată pentru citirea fișierului ( obținut cu „gratuit” și monitorizarea valorii „cache”).
  2. Dacă un alt proces încearcă să încarce același fișier (în timp ce acesta este încă rezident în cache), nucleul detectează acest lucru și nu este necesar să reîncărcați fișierul. Dacă memoria cache a paginii se completează, paginile vor fi evacuate - cele murdare vor fi scrise pe disc. (De asemenea, paginile se scriu înapoi dacă există un disc explicit pe disc și periodic, cu un fir de nucleu).
  3. Având deja un fișier (mare) în cache este o îmbunătățire semnificativă a performanței, cu atât mai mult decât diferențele bazate pe metodele Java pe care le folosim pentru a deschide / citi fișierul respectiv.
  4. Programul AC care apelează apelul la sistemul mmap poate face o mapare ANONIMĂ, care alocă în mod esențial pagini din memoria cache care nu sunt susținute de un fișier efectiv (deci nu este nevoie să emite scrieri reale pe disc), dar Java nu pare pentru a oferi asta (ar putea cartografia unui fișier în tmpfs să realizeze același lucru?)
  5. Dacă un fișier este încărcat folosind apelul de sistem mmap (C) sau prin FileChannel.map () (Java), în esență, paginile fișierului (în cache) sunt încărcate direct în spațiul de adrese al procesului. Folosind alte metode pentru a deschide un fișier, fișierul este încărcat în pagini care nu se află în spațiul de adrese al procesului, iar apoi diferitele metode pentru a citi / scrie acel fișier copiază câteva octeți din / către acele pagini într-un tampon din spațiul de adrese al procesului. . Există un beneficiu evident de performanță evitând această copie, dar întrebarea mea nu este preocupată de performanță.

Așadar, în rezumat, dacă înțeleg corect - în timp ce maparea oferă un avantaj de performanță, nu pare că oferă vreo funcționalitate „memorie partajată” pe care nu o obținem deja doar din natura Linux și a cache-ului de pagini.

Vă rog, anunțați-mă unde mi-a rămas înțelegerea.

Mulțumiri.

Întrebat 22/05/2020 la 21:20
sursa de către utilizator
În alte limbi...                            


2 răspunsuri

voturi
0

De menționat trei puncte: performanță, modificări simultane și utilizarea memoriei.

Sunteți corect în evaluare că, de obicei, pe baza MMAP va oferi un avantaj de performanță față de IO bazat pe fișiere. În particular, avantajul de performanță este semnificativ dacă codul efectuează o mulțime de mici IO la punctul artbitrary al fișierului.

Luați în considerare schimbarea octetului N: cu mmap buffer[N] = buffer[N] + 1 și cu acces bazat pe fișiere aveți nevoie (cel puțin) de 4 apeluri de sistem verificarea erorilor:

   seek() + error check
   read() + error check
   update value
   seek() + error check
   write + error check

Este adevărat că numărul de IO efectiv (la disc) este cel mai probabil același.

Al doilea punct demn de remarcat accesul concomitent. Cu IO bazat pe fișiere, trebuie să vă faceți griji în legătură cu potențialul acces simultan. Va trebui să emiteți blocarea explicită (înainte de citire) și să deblocați (după scriere), pentru a împiedica două procese pentru accesarea incorectă a valorii în același timp. Cu memoria partajată, operațiunile atomice pot elimina nevoia de blocare suplimentară.

Al treilea punct este utilizarea efectivă a memoriei. Pentru cazurile în care dimensiunea obiectelor partajate este semnificativă, utilizarea memoriei partajate poate permite unui număr mare de procese să acceseze datele fără a aloca memorie suplimentară. Dacă sistemele limitate de memorie sau sistemul care trebuie să ofere performanțe în timp real, aceasta ar putea fi singura modalitate de acces la date.

Publicat 29/05/2020 la 10:35
sursa de către utilizator

voturi
0

Întrebarea mea este: pe Java (1.8) și Linux (3.10), sunt MappedByteBuffers într-adevăr necesare pentru implementarea IPC-ului cu memorie partajată, sau ar avea acces la un fișier comun aceeași funcționalitate?

Depinde de ce doriți să implementați IPC cu memorie partajată.

Puteți implementa în mod clar IPC fără memorie partajată; de exemplu peste prize. Deci, dacă nu o faceți din motive de performanță, nu este necesar să faceți deloc IPC cu memorie partajată!

Deci performanța trebuie să stea la baza oricărei discuții.

Accesul folosind fișiere prin API-urile Java clasice io sau nio nu oferă funcționalitate sau performanță de memorie partajată.

Principala diferență între I / O de fișier obișnuit sau Socket I / O față de IPC cu memorie partajată este că primul necesită ca aplicațiile să facă explicit read și write syscalls pentru a trimite și primi mesaje. Aceasta implică sisteme suplimentare și implică copierea datelor din nucleu. În plus, dacă există mai multe fire, fie aveți nevoie de un "canal" separat între fiecare pereche de fire sau ceva pentru a multiplexa mai multe "conversații" pe un canal partajat. Acesta din urmă poate duce la transformarea canalului partajat într-un blocaj de concurență.

Rețineți că aceste cheltuieli generale sunt ortogonale pentru memoria cache a paginilor Linux.

În schimb, cu IPC implementat folosind memoria partajată, nu există read și write syscalls și niciun pas suplimentar de copiere. Fiecare „canal” poate utiliza pur și simplu o zonă separată a tamponului mapat. Un thread dintr-un proces scrie date în memoria partajată și este aproape imediat vizibil pentru cel de-al doilea proces.

Previziunea este că procesele trebuie să 1) sincronizeze și 2) să implementeze bariere de memorie pentru a vă asigura că cititorul nu vede date necuprinzătoare. Însă acestea pot fi implementate fără syscalls.

În spălare, IPC-ul cu memorie partajată folosind fișiere mapate cu memorie >> este << mai rapid decât utilizarea fișierelor sau soclurilor convenționale, și de aceea oamenii o fac.


De asemenea, ați întrebat implicit dacă IPC-ul cu memorie partajată poate fi implementat fără fișiere mapate cu memorie.

  • Un mod practic ar fi crearea unui fișier mapat cu memorie pentru un fișier care locuiește într-un sistem de fișiere cu memorie; de exemplu, un "tmpfs" în Linux.

    Tehnic, acesta este încă un fișier mapat de memorie. Cu toate acestea, nu suportați cheltuieli generale de curățare a datelor pe disc și evitați problema potențială de securitate a datelor IPC private care se termină pe disc.

  • Teoretic, puteți implementa un segment comun între două procese, urmând următoarele:

    • În procesul părinte, utilizați mmap pentru a crea un segment cu MAP_ANONYMOUS | MAP_SHARED .
    • Procesele copiilor de furcă. Acestea vor termina toate partajarea segmentului între ei și procesul părinte.

    Cu toate acestea, punerea în aplicare a acestui proces Java ar fi ... provocatoare. AFAIK, Java nu acceptă acest lucru.

Referinţă:

Publicat 31/05/2020 la 06:17
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more