Paylaşılan bellek IPC için dosyaları kullanma, bellek eşleme bir gereklilik mi?

oy
19

Java'nın FileChannel.map () tarafından döndürülen MappedByteBuffers'ı, aynı ana bilgisayardaki JVM'ler arasında paylaşılan bellek IPC'si kullanmanın bir yolu olarak kullanan birkaç proje var (bkz. Chronicle Queue, Aeron IPC, vb.). Anlayabildiğim kadarıyla, bu api sadece mmap çağrısının üstünde oturuyor. Ancak Java'nın uygulaması anonim (dosya destekli olmayan) eşleşmelere izin vermez.

Benim sorum, Java (1.8) ve Linux (3.10) üzerinde, paylaşılan bellek IPC'yi uygulamak için gerçekten MappedByteBuffers gerekli mi yoksa ortak bir dosyaya herhangi bir erişim aynı işlevselliği sağlar mı? (Bu soru, MappedByteBuffer kullanmanın performansla ilgili olmasıyla ilgili değildir.)

İşte benim anlayışım:

  1. Linux diskten bir dosya yüklediğinde, o dosyanın içeriğini bellekteki sayfalara kopyalar. Bu bellek bölgesine sayfa önbelleği denir. Anlayabildiğim kadarıyla, dosyayı okumak için hangi Java yönteminin (FileInputStream.read (), RandomAccessFile.read (), FileChannel.read (), FileChannel.map ()) veya yerel yöntemin kullanıldığından bağımsız olarak bunu yapar ( "serbest" ile gözlemlenen ve "önbellek" değerinin izlenmesi).
  2. Başka bir işlem aynı dosyayı yüklemeye çalışırsa (hala önbellekte yer alırken) çekirdek bunu algılar ve dosyayı yeniden yüklemesi gerekmez. Sayfa önbelleği dolarsa, sayfalar çıkartılır - kirli olanlar diske geri yazılır. (Sayfalar ayrıca, diske açık bir yıkama ve düzenli olarak bir çekirdek iş parçacığı varsa geri yazılır).
  3. Zaten önbellekte (büyük) bir dosya olması, bu dosyayı açmak / okumak için kullandığımız Java yöntemlerine göre farklılıklardan çok daha önemli bir performans artışıdır.
  4. Mmap sistem çağrısını çağıran AC programı, aslında önbellekteki gerçek bir dosya tarafından desteklenmeyen sayfaları ayıran ANONYMOUS eşleştirmesi yapabilir (bu nedenle diske gerçek yazma işlemi yapmaya gerek yoktur), ancak Java görünmez bunu sunmak için ( tmpfs'de bir dosyayı eşleştirmek aynı şeyi yapar mı?)
  5. Bir dosya mmap sistem çağrısı (C) veya FileChannel.map () (Java) kullanılarak yüklenirse, esasen dosyanın sayfaları (önbellekteki) doğrudan işlemin adres alanına yüklenir. Bir dosyayı açmak için diğer yöntemleri kullanarak dosya, işlemin adres alanında olmayan sayfalara yüklenir ve daha sonra bu dosyayı okumak / yazmak için çeşitli yöntemler, bu sayfalardan / bu sayfalardan bazı baytları işlemin adres alanındaki bir arabelleğe kopyalar . Bu kopyadan kaçınan belirgin bir performans avantajı var, ancak sorum performansla ilgili değil.

Özetle, doğru anlarsam - haritalama bir performans avantajı sunarken, sadece Linux'un ve sayfa önbelleğinin doğasından almadığımız herhangi bir "paylaşılan bellek" işlevselliği sunuyor gibi görünmüyor.

Lütfen, anlayışımın nerede olduğunu bana bildirin.

Teşekkürler.

Oluştur 22/05/2020 saat 21:20
kaynak kullanıcı
Diğer dillerde...                            


2 cevaplar

oy
0

Üç noktadan bahsetmeye değer: performans ve eşzamanlı değişiklikler ve bellek kullanımı.

MMAP tabanlı, genellikle dosya tabanlı ES'ye göre performans avantajı sunacağını değerlendirmede haklısınız. Özellikle, kod dosyanın keyfi noktasında çok sayıda küçük GÇ gerçekleştirirse performans avantajı önemlidir.

N-bayt değerini değiştirmeyi düşünün: mmap ile buffer[N] = buffer[N] + 1 ve dosya tabanlı erişimle (en azından) 4 sistem çağrısı hata kontrolü yapmalısınız:

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

Gerçek IO (diske) sayısının büyük olasılıkla aynı olduğu doğrudur.

Eşzamanlı erişime dikkat çeken ikinci nokta. Dosya tabanlı ES ile, eşzamanlı potansiyel erişim konusunda endişelenmeniz gerekir. İki işlemin değere aynı anda yanlış erişmesini önlemek için açık kilitleme (okumadan önce) ve kilidini açmanız (yazma işleminden sonra) yapmanız gerekir. Paylaşılan bellekle, atomik işlemler ek kilit ihtiyacını ortadan kaldırabilir.

Üçüncü nokta, gerçek bellek kullanımıdır. Paylaşılan nesnelerin boyutunun önemli olduğu durumlarda, paylaşılan hafıza kullanılması, ek hafıza tahsis etmeden çok sayıda işlemin verilere erişmesine izin verebilir. Bellek tarafından kısıtlanan sistemler veya gerçek zamanlı performans sağlaması gereken sistemse, verilere erişmenin tek yolu bu olabilir.

Cevap 29/05/2020 saat 10:35
kaynak kullanıcı

oy
0

Benim sorum, Java (1.8) ve Linux (3.10) üzerinde, paylaşılan bellek IPC'yi uygulamak için gerçekten MappedByteBuffers gerekli mi yoksa ortak bir dosyaya herhangi bir erişim aynı işlevselliği sağlar mı?

Neden paylaşılan bellek IPC'sini uygulamak istediğinize bağlıdır.

Paylaşılan bellek olmadan IPC'yi açıkça uygulayabilirsiniz; örneğin soketlerin üzerinde. Bu nedenle, performans nedenleriyle yapmıyorsanız, paylaşılan bellek IPC'si yapmak gerekli değildir!

Bu yüzden performans herhangi bir tartışmanın temelinde olmalıdır.

Java classic io veya nio API'leri aracılığıyla dosya kullanarak erişim, paylaşılan bellek işlevselliği veya performansı sağlamaz.

Paylaşılan bellek IPC'ye karşı normal dosya G / Ç veya Soket G / Ç arasındaki temel fark, eskisinin uygulamaların açıkça yapmasını gerektirmesidir. read ve write mesaj göndermek ve almak için syscalls. Bu, ekstra sistem çağrılarını ve çekirdek kopyalama verilerini gerektirir. Ayrıca, birden çok iş parçacığı varsa, her iş parçacığı çifti arasında ayrı bir "kanala" ya da paylaşılan bir kanal üzerinden birden çok "konuşmayı" çoğaltmaya ihtiyacınız vardır. İkincisi, paylaşılan kanalın eşzamanlı bir darboğaz haline gelmesine neden olabilir.

Bu ek yüklerin Linux sayfa önbelleğine dik olduğunu unutmayın.

Bunun aksine, paylaşılan bellek kullanılarak uygulanan IPC ile, read ve write syscalls ve ekstra kopya adımı yok. Her "kanal", eşlenen tamponun ayrı bir alanını kullanabilir. Bir işlemdeki bir iş parçacığı, verileri paylaşılan belleğe yazar ve ikinci işlem tarafından hemen görülebilir.

Uyarı, işlemcinin okuyucunun eski verileri görmediğinden emin olmak için 1) senkronize etmesi ve 2) bellek engelleri uygulaması gerektiğidir. Ancak bunların ikisi de sistem çağrısı olmadan uygulanabilir.

Yıkamada, bellek eşlemeli dosyaları kullanan paylaşılan bellek IPC'si >>, geleneksel dosyaları veya soketleri kullanmaktan daha hızlıdır ve bu yüzden insanlar bunu yapar.


Paylaşılan bellek IPC'sinin bellek eşlemeli dosyalar olmadan uygulanıp uygulanamayacağını da sordunuz.

  • Pratik bir yol, sadece bellek dosya sisteminde yaşayan bir dosya için bellek eşlemeli bir dosya oluşturmak olabilir; örneğin Linux'ta bir "tmpfs".

    Teknik olarak, bu hala bellek eşlemeli bir dosyadır. Ancak, verileri diske akıtma yükleri oluşturmazsınız ve özel IPC verilerinin diskte bitmesi gibi olası güvenlik sorunlarından kaçınırsınız.

  • Teorik olarak , aşağıdakileri yaparak iki işlem arasında paylaşılan bir segment uygulayabilirsiniz:

    • Üst işlemde, ile bir segment oluşturmak için mmap kullanın MAP_ANONYMOUS | MAP_SHARED .
    • Çatal alt süreçleri. Bunlar, segmentin birbiriyle ve ana süreçle paylaşılmasıyla sonuçlanır.

    Ancak, bunu bir Java işlemi için uygulamak zor olabilir. AFAIK, Java bunu desteklemiyor.

Referans:

Cevap 31/05/2020 saat 06:17
kaynak kullanıcı

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