"Yığın üzerinde" ve "yığın dışı" arasındaki fark


Yanıtlar:


173

Yığın üzerinde depo, Java yığınında bulunacak (ve ayrıca GC'ye tabi olan) nesnelere başvurur. Öte yandan, yığın dışı depo, EHCache tarafından yönetilen, ancak yığın dışında depolanan (ve ayrıca GC'ye tabi olmayan) nesnelere (serileştirilmiş) başvurur. Yığın dışı depo bellekte yönetilmeye devam ederken, yığın depodan biraz daha yavaştır, ancak yine de disk deposundan daha hızlıdır.

Yığın dışı deponun yönetimi ve kullanımıyla ilgili dahili ayrıntılar, soruda yayınlanan bağlantıda çok belirgin değildir, bu nedenle disk dışı verileri yönetmek için kullanılan Terracotta BigMemory'nin ayrıntılarını kontrol etmek akıllıca olacaktır. mağaza. BigMemory (yığın dışı depo), birkaç Megabayt veya Gigabayt büyüklüğündeki bir yığın üzerindeki GC ek yükünden kaçınmak için kullanılacaktır. BigMemory, diğer yerel Java nesnelerinin aksine GC'ye tabi olmayan doğrudan ByteBuffers aracılığıyla JVM işleminin bellek adres alanını kullanır .


18
Daha fazla keşif için doğrudan ByteBuffers'dan bahsetmek için +1;)
Max

3
Doğrudan ByteBuffers, yönetilmeyen belleğe erişim sağlar, ancak kendileri GC'ye tabidir (işaret ettikleri verilerin aksine). Bu önemlidir çünkü doğrudan bir ByteBuffer (MMap türü değil, ByteBuffer.allocateDirect türü) GC tarafından toplanacak ve toplandığında Deallocater tetiklenecek ve yönetilmeyen belleği de etkin bir şekilde toplayacaktır.
Nitsan Wakart

Nesneleri ayırmak için Unsafe'i kullanmak, Onheap / DirectByteBuffers / ByteBuffers'a göre önemli ölçüde daha iyi okuma ve yazma performansına sahip gibi görünüyor. ashkrit.blogspot.com/2013/07/…
Joe C

100

dan http://code.google.com/p/fast-serialization/wiki/QuickStartHeapOff

Yığın Boşaltma nedir?

Genellikle, ayırdığınız tüm geçici olmayan nesneler java'nın çöp toplayıcısı tarafından yönetilir. Sanal makine çöp toplama yaparak iyi bir iş çıkarsa da, belirli bir noktada sanal makinenin 'Tam GC' adı verilen bir iş yapması gerekir. Tam bir GC, tahsis edilmiş Yığının tamamının taranmasını içerir; bu, GC duraklamalarının / yavaşlamalarının bir uygulama yığını boyutuyla orantılı olduğu anlamına gelir. Bu yüzden size 'Hafıza Ucuzdur' diyen kimseye güvenmeyin. Java'da bellek tüketimi performansa zarar verir. Ek olarak, yığın boyutlarını> 1 Gb kullanarak dikkate değer duraklamalar elde edebilirsiniz. Neredeyse gerçek zamanlı herhangi bir şeyiniz varsa, bir küme veya ızgarada bir java işlemi yanıt vermeyebilir ve kümeden düşebilir.

Ancak günümüzün sunucu uygulamaları (sıklıkla şişkin çerçeveler üzerine inşa edilmiştir ;-)) kolaylıkla 4 Gb'nin çok ötesinde yığınlar gerektirir.

Bu bellek gereksinimlerine bir çözüm, nesnelerin parçalarını java olmayan yığına (doğrudan işletim sisteminden tahsis edilir) 'boşaltmaktır'. Neyse ki java.nio, 'yönetilmeyen' bellek parçalarını (bellek eşlemeli dosyalar bile) doğrudan ayırmak / okumak ve yazmak için sınıflar sağlar.

Bu nedenle, büyük miktarlarda 'yönetilmeyen' bellek tahsis edilebilir ve bu bellek oradaki nesneleri kaydetmek için kullanılabilir. Rastgele nesneleri yönetilmeyen belleğe kaydetmek için en uygun çözüm Serileştirmenin kullanılmasıdır. Bu, uygulamanın nesneleri yığın dışı belleğe serileştirdiği anlamına gelir, daha sonra nesne seriyi kaldırma kullanılarak okunabilir.

Java sanal makinesi tarafından yönetilen yığın boyutu küçük tutulabilir, bu nedenle GC duraklamaları milis içindedir, herkes mutludur, iş bitti.

Açıktır ki, böyle bir yığın dışı arabelleğin performansı çoğunlukla serileştirme uygulamasının performansına bağlıdır. İyi haber: bazı nedenlerden dolayı FST-serileştirme oldukça hızlı :-).

Örnek kullanım senaryoları:

  • Bir sunucu uygulamasında oturum önbelleği. Gigabaytlarca (etkin olmayan) kullanıcı oturumunu depolamak için bellek eşlemeli bir dosya kullanın. Kullanıcı uygulamanızda oturum açtığında, bir veritabanıyla uğraşmak zorunda kalmadan kullanıcıyla ilgili verilere hızlı bir şekilde erişebilirsiniz.
  • Hesaplama sonuçlarının önbelleğe alınması (sorgular, html sayfaları, ..) (yalnızca hesaplama, c'nin sonuç nesnesinin serisini kaldırmadan daha yavaşsa uygulanabilir).
  • bellek eşlemeli dosyaları kullanarak çok basit ve hızlı süreklilik

Düzenleme: Bazı senaryolar için, daha büyük yığınları desteklemek için ConcurrentMarkAndSweep veya G1 gibi daha karmaşık Atık Toplama algoritmaları seçilebilir (ancak bunun 16 GB'lık yığınların ötesinde sınırları da vardır). Ayrıca geliştirilmiş 'duraksız' GC (Azul) ile ticari bir JVM mevcuttur.


4
"büyük miktarlarda 'yönetilmeyen' bellek ayırın ve bunu nesneleri oraya kaydetmek için kullanın" - Nesneleri farklı bir yere kaydedemezsiniz. İlkelleri saklayabilirsiniz, onları istediğiniz kütüphaneye sarabilirsiniz, ancak bunlar Nesneler değildir. Yerleştirdiğiniz verilerin nesne başlığı yoktur, üzerinde senkronize edemezsiniz, başka bir nesnedeki bir referans alanıyla ona başvuramazsınız.
Nitsan Wakart

42

Yığın, dinamik olarak tahsis edilmiş nesnelerinizin yaşadığı bellekteki yerdir. Kullandıysanız new, yığın üzerindedir. Bu, işlev yığınının yaşadığı yer olan yığın boşluğunun aksine. Yerel bir değişkeniniz varsa, bu başvuru yığın üzerindedir. Java'nın yığını çöp toplamaya tabidir ve nesneler doğrudan kullanılabilir.

EHCache'nin yığın dışı depolama alanı, normal nesnenizi yığından alır, seri hale getirir ve EHCache'nin yönettiği bir bellek yığınında bayt olarak depolar. Diske depolamak gibi ama yine de RAM'de. Nesneler bu durumda doğrudan kullanılamaz, önce seri durumlarının kaldırılması gerekir. Ayrıca çöp toplamaya tabi değildir.


Hâlâ yığın halinde değil, serileştirilmiş bir form olarak değil mi?
Pacerier

1
bu onu nasıl daha verimli kılar?
Pacerier

2
Birçok yol var. Nesneler artık ana Java yığınında olmadığından, çöp toplayıcının zamanını boşa harcamıyorlar, JVM yığınını parçalamıyorlar ve daha çok kullanılan diğer nesneler için yer açıyorlar. Ayrıca, seri hale getirildikleri ve muhtemelen yakın gelecekte ihtiyaç duyulmadıkları için sıkıştırılabilir, gerektiğinde taşınabilir ve hatta diske sayfalanabilir.
Adam

1
Hotspot'ta, GC duraklatma süresi doğrudan yığın boyutuna bağlıdır. BigMemory, GC duraklamasını minimumda tutmak ve disk erişiminin GÇ maliyetinden kaçınmak için yığın yerine RAM kullanarak bu ticareti sağlar.
Chander Shivdasani

@Adam Cevabınız için teşekkürler, "bayt olarak depolar" dediğinizde bu tam olarak ne anlama geliyor? Aslında soruyu stackoverflow.com/questions/63320051/… adresinde gündeme getirdim ama yanıt alamadım, herhangi bir ipucunuz var mı? Teşekkürler.
jack


1

JVM, yığın dışı bellek hakkında hiçbir şey bilmiyor. Ehcache, hem bir disk üzerinde önbellek hem de bir bellek içi önbellek uygular.


1

% 100 değil; ancak, öbek, Java'nın kendisinin veya ehcache'nin kendisinden büyük olasılıkla kodun işlevselliğine yerleşik bir nesne veya tahsis edilmiş alan kümesi (RAM'de) gibi görünüyor ve yığın dışı Ram, şu şekilde kendi sistemi var mı? iyi; ancak, bu kadar organize olmadığı için bir kat daha yavaş gibi görünüyor, yani bir yığın kullanmayabilir (uzun bir ram alanı anlamına gelir) ve bunun yerine muhtemelen onu biraz daha az verimli hale getiren farklı adres alanları kullanır.

O zaman elbette bir sonraki alt katman, sabit sürücü alanının kendisidir.

Ben ehcache kullanmıyorum, bu yüzden bana güvenmek istemeyebilirsiniz, ama onların belgelerinden öğrendiğim şey buydu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.