Soru Java'da hafıza nasıl boşaltılır?


Java’da hafızayı boşaltmanın bir yolu var mı? free() işlev? Ya da nesneyi null olarak ayarlamak ve GC'ye tek seçeneğe güvenmek mi?


119
2017-10-14 17:58


Menşei


Tamam ... bir şeyi düzelelim. Sadece bir şeyin kötü bir uygulama olduğunu ve bunu yapmaya teşvik edecek bir şey olmadığını düşündüğünüz için, oylamaya layık değildir. Bu, Java'da belleğin çöp toplama yöntemine dayanarak yayınlanması için bir yol olup olmadığını sorduğumuz açık ve geçerli bir sorudur. Cesaretsiz ve genel olarak yararlı veya iyi bir fikir olmasa da, Felix'in ne bildiğini bilmeden gerekli olabilecek senaryoların olmadığını bilemezsiniz. Felix onu kullanmayı bile planlamadı. Sadece mümkün olup olmadığını bilmek isteyebilir. Hiçbir şekilde, oylamayı hak etmiyor. - Daniel Bingham
Açıklık getirmek için, bu kime oy vermeyi amaçladı - önceki yorumlara mutlaka değil. - Daniel Bingham


Cevaplar:


Java, yönetilen belleği kullanır, böylece belleği ayırabilmenin tek yolu, new operatör ve belleği ayırabilmenin tek yolu çöp toplayıcısına güvenmektir.

Bu bellek yönetimi (PDF) neler olduğunu açıklamaya yardımcı olabilir.

Ayrıca arayabilirsiniz System.gc() Çöp toplayıcının hemen çalıştırıldığını önermek için. Ancak, Java Runtime kodunuzu değil, son kararı verir.

Göre Java belgeleri,

Gc yöntemini çağırmak şunu önerir:   Java Sanal Makinesi harcama çabası   Kullanılmayan nesneleri geri dönüşüme doğru   hafıza yapmak için sipariş   şu an için hızlı kullanılabilir   yeniden kullanın. Kontrolden döndüğünde   yöntem çağrısı, Java Sanal Makinesi   geri almak için en iyi çabayı gösterdi   tüm atılan nesnelerden alan.


85
2017-10-14 18:01



Çöp Toplayıcısını çalıştırmaya zorlar. Hafızayı serbest bırakmak zorunda değil ama ... - Pablo Santa Cruz
Pablo yok, GC'yi koşmaya zorlamaz. - Jesper
TAMAM. Anlıyorum. Bunu işaret ettiğin için teşekkürler. - Pablo Santa Cruz
Tüm HotSpotVM'nin çöp toplayıcılarının görmezden geldiği çok güvenilir bir kişi tarafından söylendi System.gc() Baştan sona. - Esko
WinXp java SE GC, her System.gc () işlevini çalıştırır veya hemen hemen her bir API doc bunu garanti etmez. - teodozjan


Hiç kimse açıkça nesne başvuruları belirten söz etmiş gibi görünüyor null, düşünmek isteyebileceğiniz "özgür" bellek için meşru bir tekniktir.

Örneğin, bir List<String> büyüklüğünde büyüdüğü bir yöntemin başlangıcında, ancak büyük ölçüde yöntemin yarısına kadar gerekliydi. Bu noktada, List null Çöp toplayıcının, yöntem tamamlanmadan önce bu nesneyi potansiyel olarak geri almasına izin vermek için (ve başvuru yine de kapsam dışıdır).

Bu tekniği nadiren kullandığımı fakat çok büyük veri yapılarıyla uğraşırken dikkate almam gerektiğini unutmayın.


58
2017-10-14 19:50



Eğer gerçekten bir yöntemin parçası olarak kullanılan bir nesne üzerinde çok fazla iş yapıyorsanız, ya şunu öneriyorum; yönteminiz çok komplike, yöntemi önce ve sonra bölümleri kırmak veya kodun ilk yarısı için bir blok kullanın (daha sonra test komut dosyaları için daha yararlıdır) - Peter Lawrey
Nesne başvurusunun null değerine ayarlanmasının önemli olduğu yer, başka bir uzun ömürlü nesneden (ya da muhtemelen bir statik varyasyondan) referans alındığı zamandır. Örneğin, uzun ömürlü büyük nesneler dizisi varsa ve bu nesnelerden birini kullanmayı bırakırsanız, nesneyi GC için kullanılabilir hale getirmek için dizi başvurusunu null olarak ayarlamanız gerekir. - Hot Licks


System.gc(); 

Çöp toplayıcısını çalıştırır.

  Gc yöntemini çağırmak anlaşılacağı Java Sanal Makinesinin, kullanılmakta olan nesneleri hızlı bir şekilde yeniden kullanmak için kullanabildikleri belleğe dönüştürmek amacıyla kullanılmayan nesneleri geri dönüştürmeye harcadığı çabası. Denetim, yöntem çağrısından döndüğünde, Java Virtual Machine tüm atılan nesnelerden alan kazanmak için en iyi çabayı göstermiştir.

Tavsiye edilmez.

Düzenleme: Orijinal yanıtı 2009'da yazdım. Şimdi 2015.

Çöp toplayıcıları ~ 20 yıl içinde sürekli olarak daha iyi bir hale geldi. Bu noktada, çöp toplayıcısını manuel olarak çağırıyorsanız, diğer yaklaşımları düşünmek isteyebilirsiniz:

  • Sınırlı sayıda makinede GC'yi zorlarsanız, yük dengeleyici bir noktaya sahip olmaya değer olabilir. uzakta Mevcut makineden, bağlı istemcilere hizmet vermeyi bitirmek için bekler, bağlantı askıları için bir süre sonra zaman aşımı ve daha sonra JVM'yi yeniden başlatır. Bu korkunç bir çözümdür, ancak System.gc () 'ye bakıyorsanız, zorunlu yeniden başlatmalar olası bir durma olabilir.
  • Farklı bir çöp toplayıcı kullanmayı düşünün. Örneğin, (son altı yılda yeni) G1 toplayıcı düşük duraklama modelidir; Genel olarak daha fazla CPU kullanır, ancak hiçbir zaman yürütme sırasında zorlamayı zorlamak en iyisidir. Sunucu CPU'larının hemen hemen hepsinin birden fazla çekirdeği olması nedeniyle, bu, mevcut olması için Gerçekten İyi Bir Tradeoff.
  • Bellek kullanımını ayarlama bayraklarına bakın. Özellikle Java'nın daha yeni sürümlerinde, çok uzun süreli çalışan nesneleriniz yoksa, yığıntaki newgen boyutunu küçültmeyi düşünün. newgen (genç) yeni nesnelerin tahsis edildiği yerdir. Bir web sunucusu için, bir istek için oluşturulan her şey buraya konur ve eğer bu alan çok küçükse, Java, nesneleri daha uzun ömürlü belleğe yükseltmek için daha fazla zaman harcayacak, böylece öldürmeleri daha pahalı olacaklardır. (Eğer newgen biraz küçükse, bunun bedelini ödeyeceksiniz.) Örneğin, G1’de:
    • XX: G1NewSizePercent (varsayılanı 5'e; muhtemelen önemli değil)
    • XX: G1MaxNewSizePercent (varsayılanı 60'tır; büyük ihtimalle bunu artırır.)
  • Çöp toplayıcısına daha uzun bir duraklama ile iyi olmadığınızı düşünün. Bu, sistemin kısıtlamalarının geri kalanını tutmasına izin vermek için daha sık GC çalışmalarına neden olur. G1’de:
    • XX: MaxGCPauseMillis (varsayılanı 200'e kadardır.)

22
2017-10-14 18:01



Kendi gönderimime yorum yaptığımda, bu genellikle bir şey yapmaz ve tekrar tekrar çağırmak, JVM'nin kararsız hale gelmesine neden olabilir. Köpeğinizin üzerinden de geçebilir; dikkatle yaklaşmak. - Dean J
"Gk yönteminin çağrılması, JVM'nin çabaları arttırdığını öne sürüyor" bölümünde "düşündüren" kısmına ağır bir vurgu yapardım. - matt b
@Jesper, Dean'in cevabı "önerir" diyor. Aslında, yöntemin javadocs'ından tam bir belge yayınladı ... - matt b
@ Yazılım Maymun: Evet, daha yeni düzenleyebilirdim. Fakat Dean J'nin açıkça aktif olduğu (sadece birkaç dakika önce) olduğu için, bunu yapmasını istemek nezaket olduğunu düşündüm. Eğer olmasaydı, buraya geri dönüp düzenlemeyi yapardım ve yorumumu silerdim. - Daniel Pryden
Ayrıca, NEDEN önerilmiyor? JVM, GC'yi çalıştırmak için "öneri" konusuna önem veriyorsa, muhtemelen uygulamanızın büyük olasılıkla birçok büyüklük sırasına göre daha yavaş çalışmasını sağlayacaktır! - Stephen C


* "Ben şahsen nulling değişkenleri gelecekteki uygun bir silme için bir yer tutucu olarak güveniyorum. Örneğin, ben aslında diziyi (null) silmeden önce bir dizinin tüm unsurları geçersiz kılmak için zaman ayırın."

Bu gereksizdir. Java GC'nin çalışma şekli, bunlara referans olmayan nesneler bulur, dolayısıyla bir referans (= değişken) ile bir Object x var ise, bu noktaya işaret eder, GC bunu silmez, çünkü bir referans vardır bu nesneye:

a -> x

Eğer bir null olursa, bu olur:

a -> null
     x

Yani şimdi x'in kendisine işaret eden bir referansı yok ve silinecek. Aynı şey, x'den farklı bir nesneyi referans olarak ayarladığınızda da olur.

Yani, x, y ve z nesnelerine başvurulan bir dizi arrınız varsa ve diziye başvuran bir değişkene benziyorsa:

a -> arr -> x
         -> y
         -> z

Eğer bir null olursa, bu olur:

a -> null
     arr -> x
         -> y
         -> z

Bu yüzden GC, kendisine hiçbir referans seti koymadığını ve silenize sahip olduğunu bulur:

a -> null
     x
     y
     z

Şimdi GC x, y ve z'yi bulur ve onları siler. Dizideki her bir referansı geçersiz kılmak, daha iyi bir şey yapmayacaktır, sadece CPU zamanını ve koddaki alanı kullanacaktır (bu, bundan daha fazla zarar vermeyeceğini söylemektedir. GC, yine de gereken şekilde çalışacaktır. ).


11
2018-01-25 20:28





Herhangi bir programdan (java ya da değil) hafızayı boşaltmak için geçerli bir sebep, işletim sistemi seviyesinde diğer programlara daha fazla bellek sağlamaktır. Java uygulamam 250 MB kullanıyorsa, onu 1MB'a zorlamak ve 249MB'ı diğer uygulamalar için kullanılabilir hale getirmek isteyebilirim.


6
2018-03-27 08:18



Bir Java programında 249MB'lık bir parçayı açıkça serbest bırakmanız gerekiyorsa, bellek yönetimi üzerinde çalışmak istediğim ilk şey olmazdı. - Marc DiMillo
Ancak Java yığınınızda depolama alanı boşaltmak (genel durumda) depolama alanını diğer uygulamalarda kullanılabilir yapmaz. - Hot Licks


Bu konuda deney yaptım.

Olduğu doğru System.gc(); Sadece Çöp Toplayıcısını çalıştırmayı önerir.

Ama aramak System.gc(); tüm referansları ayarladıktan sonra nullperformans ve hafıza işgalini geliştirecek.


5
2018-03-10 19:05



"System.gc () işlevini çağırmak," tüm başvuruları sıfır olarak ayarladıktan sonra, performans ve bellek işini artıracağından "emin olamazsınız." Çünkü System.gc () 'nin büyük hesaplama karmaşıklığı vardır. Ve System.gc () 'yi çağırdıktan ve gerçekten çöp topladıktan sonra, jvm belleği OS veya Sistem'e geri vermeyebilir. JVM, gelecekteki başvurular için belleği koruyabilir. Bunu gör Cevap. - Md. Abu Nafee Ibna Zahid


Yiannis Xanthopoulos ve Hot Licks'in cevabını ve yorumunu genişletmek için (özür dilerim, henüz yorum yapamıyorum!), Bu örnek gibi VM seçeneklerini ayarlayabilirsiniz:

-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30

Benim jdk 7'de, VM boştayken GC'den sonra yığının% 30'undan daha fazla serbest kalırsa, bu kullanılmayan VM belleğini serbest bırakır. Bu parametreleri ayarlamanız gerekecektir.

Aşağıdaki bağlantıda vurgulanan görmedim, bazı çöp toplayıcıları bu parametrelere uymayabilir ve varsayılan olarak java sizin için bunlardan birini seçebilir, birden fazla çekirdeğe sahip olabilirsiniz (bu nedenle yukarıdaki UseG1GC argümanı) ).

VM argümanları

Güncelleme: java 1.8.0_73 için JVM'nin, bazen varsayılan ayarlarla küçük miktarlar yayınladığını gördüm. Sadece yığının ~% 70'i kullanılmıyorsa bunu yapmak görünür. Eğer işletim sistemi fiziksel bellekte düşükse daha agresif bir sürüm olup olmayacağını bilmiyorum.


4
2018-04-15 12:03





Gerçekten bir bellek bloğu ayırmak ve boşaltmak istiyorsanız, bunu doğrudan ByteBuffers ile yapabilirsiniz. Belleği boşaltmak için taşınabilir olmayan bir yol bile var.

Ancak, önerildiği gibi, sadece C'de hafızayı boşaltmanız gerektiğinden, bunu yapmak zorunda olmak iyi bir fikir değildir.

Eğer gerçekten iyi bir kullanım durumunuz olduğunu düşünüyorsanız (), lütfen soruya dahil edin, ne yapacağınızı görebilmemiz için, daha iyi bir yol olması muhtemeldir.


3
2017-07-13 19:58





Tamamen javacoffeebreak.com/faq/faq0012.html

Düşük öncelikli bir iş parçacığı otomatik olarak çöp toplama ile ilgilenir   kullanıcı için. Boşta kalma süresi boyunca, iş parçacığı üzerine çağrılabilir ve   Java'da önceden bir nesneye ayrılmış belleği boşaltmaya başlayabilir.   Ama endişelenme - senin üzerindeki nesnelerini silmez!

Bir nesneye referans olmadığında, bu oyun için adil bir oyun olur.   çöp toplayıcı. Bazı rutinleri çağırmaktan ziyade   C ++), yalnızca nesneye yapılan tüm referansları null olarak atarsınız veya   referansa yeni bir sınıf atamak.

Örnek :

public static void main(String args[])
{
  // Instantiate a large memory using class
  MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192);

  // Do some work
  for ( .............. )
  {
      // Do some processing on myClass
  }

  // Clear reference to myClass
  myClass = null;

  // Continue processing, safe in the knowledge
  // that the garbage collector will reclaim myClass
}

Kodunuz büyük miktarda bellek istemekse,   çöp toplayıcısını alan yerine talep etmeye başlamak istiyor   Düşük öncelikli bir iplik olarak bunu yapmaya izin vermekten daha fazla. Bunu yapmak için, ekle   kodunuza aşağıdaki

System.gc();

Çöp toplayıcı, boş alanı geri almaya çalışacaktır.   Uygulama, yeniden boyutlandırıldığı kadar bellekle yürütmeye devam edebilir   Mümkün (belirli bölümlerde bellek parçalanması sorunları olabilir).


2
2018-04-17 18:23