Zor olsa bile, Java'da çöp toplamayı zorlamak mümkün mü? Ben biliyorum System.gc();
ve Runtime.gc();
sadece GC yapmayı öneriyorlar. GC'yi nasıl zorlayabilirim?
Zor olsa bile, Java'da çöp toplamayı zorlamak mümkün mü? Ben biliyorum System.gc();
ve Runtime.gc();
sadece GC yapmayı öneriyorlar. GC'yi nasıl zorlayabilirim?
Yanıtlar:
En iyi seçeneğiniz, System.gc()
çöp toplayıcısına bir koleksiyon yapmasını istediğiniz ipucunu aramaktır. Çöp toplayıcı belirleyici olmadığından zorla derhal toplanmanın bir yolu yoktur .
non-deterministic == trouble
GC.Collect()
toplamaz. Java da gc()
yapar.
Jlibs kütüphane çöp toplama için iyi bir yardımcı sınıf vardır . WeakReference nesneleriyle şık küçük bir numara kullanarak çöp toplamayı zorlayabilirsiniz .
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
PhantomReference
ile kullanmaktır ReferenceQueue
ve sonra kesinleşmeden sonra, ancak yine de temizlemeden önce bildirim alırsınız. Son olarak, bu nesnenin belleğinin geri kazanıldığını başarılı bir şekilde tespit etseniz bile, HotSpot'unki gibi yeni bir GC'de çok az şey ifade eder. Genellikle genç neslin temizlenmesi ile çakışır.
System.gc(); System.gc();
, ancak bundan daha iyi çalışıp çalışmadığını bilmek ilginç olacaktır. Aslında, sadece kaç kez aradığını yazdırmak System.gc()
yeterli olacaktır. Hiç 2'ye ulaşma şansı oldukça zayıf.
Bir GC'yi zorlamanın en iyi yolu (sadece değil) özel bir JVM yazmaktır. Çöp toplayıcıların takılabilir olduğuna inanıyorum, bu yüzden muhtemelen mevcut uygulamalardan birini seçip düzenleyebilirsiniz.
Not: Bu kolay bir cevap DEĞİLDİR.
Kullanılması Java'nın ™ Sanal Makine Aracı Arayüzü (JVM TI) , fonksiyon
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
"Sanal Makineyi bir çöp toplama işlemi yapmaya zorlar." JVM TI, JavaTM Platform Hata Ayıklayıcı Mimarisinin (JPDA) bir parçasıdır .
EVET Yöntemleri aynı sırayla çağırmak zorunda kalmanız neredeyse mümkündür ve aynı zamanda bunlar:
System.gc ();
System.runFinalization ();
bu iki yöntemin aynı anda kullanımını temizlemek için yalnızca bir nesne olsa bile, çöp toplayıcıya, finalise()
atanan belleği serbest bırakan vefinalize()
yöntemin belirttiği .
ANCAK bunun kullanımının bellek daha kötü olabilir yazılıma aşırı yük tanıtmak çünkü çöp toplayıcı kullanmak için korkunç bir uygulamadır, çöp toplayıcı kontrol artı bağlı mümkün değildir kendi iş parçacığı vardır gc tarafından kullanılan algoritma daha fazla zaman alabilir ve çok verimsiz olarak kabul edilir, kesinlikle kırıldığı için gc'nin yardımıyla en kötü yazılımınızı kontrol etmelisiniz, iyi bir çözüm gc'ye bağlı olmamalıdır.
NOT: sadece akılda tutmak için bu sadece sonlandırma yönteminde nesnenin yeniden atanması değilse çalışır, eğer bu gerçekleşirse nesne canlı kalacaktır ve teknik olarak mümkün olan bir diriliş olacaktır.
gc()
, sadece bir çöp toplama çalıştırmak için bir ipucu. runFinalizers()
yalnızca "atıldığı tespit edilen" nesneler üzerinde sonlandırıcılar çalıştırır. Gc gerçekten çalışmadıysa, böyle bir nesne olmayabilir ...
OutOfMemoryError belgelerinde , VM tam bir çöp toplama işleminden sonra belleği geri alamadığı sürece atılamayacağını bildirir. Bu nedenle, hatayı alana kadar bellek ayırmaya devam ederseniz, zaten tam bir çöp toplama zorlamış olursunuz.
Muhtemelen gerçekten sormak istediğin soru "Çöp toplayarak geri kazanmam gerektiğini düşündüğüm hafızayı nasıl geri alabilirim?"
GC'yi manuel olarak istemek için (System.gc () öğesinden değil):
.gc gelecekteki sürümlerde eleme adayıdır - Bir Güneş Mühendisi bir keresinde dünyada yirmiden az kişinin aslında nasıl kullanılacağını bildiğini yorumladı .gc () - Dün gece birkaç saat boyunca merkezi / kritik bir iş yaptım SecureRandom tarafından üretilen veri yapısı, vm sadece işaretçiler tükenmiş gibi yavaş yavaş 40.000 nesnelerin bir yerde üretti. Açıkçası, 16-bit işaretçi tablolarını boğuyordu ve klasik "başarısız makineler" davranışını sergiledi.
-Xms ve benzeri denedim, yaklaşık 57, xxx bir şey çalışana kadar biraz twiddling tuttu. Daha sonra, bir gc'den () sonra 57,127'den 57,128'e kadar gc'yi çalıştıracaktı - Easy Money kampında kod blokajı hızında.
Tasarımınızın temel olarak yeniden çalışmaya ihtiyacı vardır, muhtemelen kayan bir pencere yaklaşımı.
Komut satırından bir GC'yi tetikleyebilirsiniz. Bu toplu iş / crontab için yararlıdır:
jdk1.7.0/bin/jcmd <pid> GC.run
Görmek :
JVM spesifikasyonu çöp toplama hakkında özel bir şey söylemez. Bu nedenle, satıcılar GC'yi kendi yollarına uygulamakta özgürdürler.
Dolayısıyla bu belirsizlik, çöp toplama davranışında belirsizliğe neden olmaktadır. Çöp toplama yaklaşımları / algoritmaları hakkında bilgi edinmek için JVM ayrıntılarınızı kontrol etmelisiniz. Ayrıca davranışı özelleştirme seçenekleri de vardır.
Çöp toplamaya zorlamanız gerekiyorsa, belki de kaynakları nasıl yönettiğinizi düşünmelisiniz. Bellekte kalan büyük nesneler mi oluşturuyorsunuz? Disposable
Arabirimi olan ve dispose()
işiniz bittiğinde çağırmayan büyük nesneler mi (örneğin, grafik sınıfları) mı oluşturuyorsunuz? Sınıf düzeyinde yalnızca tek bir yöntemle ihtiyacınız olan bir şey mi söylüyorsunuz?
Çöp toplamaya neden ihtiyacınız olduğunu açıklarsanız daha iyi olur. SWT kullanıyorsanız, Image
ve Font
boş bellek gibi kaynakları atabilirsiniz . Örneğin:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
Maruz bırakılmamış kaynakları belirlemek için araçlar da vardır.
Bellek OutOfMemoryException
yetersiz ve almak bir java için kullanılabilir yığın alanı miktarını artırmak yerine deneyebilirsiniz java -Xms128m -Xmx512m
sadece yerine program java
. Bu size ilk yığın boyutunu 128Mb ve maksimum 512Mb verir, bu da standart 32Mb / 128Mb'den çok daha fazladır.
java -Xms512M -Xmx1024M
Başka bir seçenek yeni nesneler oluşturmamaktır.
Java'da GC ihtiyacını azaltmak için nesne havuzlaması uzaktadır.
Nesne havuzu oluşturma genellikle Nesne oluşturma işleminden daha hızlı olmayacaktır (hafif nesneler için esp), ancak Çöp Toplama işleminden daha hızlıdır. 10.000 nesne oluşturduysanız ve her nesne 16 baytsa. GC'nin geri alması gereken 160.000 bayt. Öte yandan, aynı anda 10.000 adete ihtiyacınız yoksa, yeni nesneler oluşturma ihtiyacını ortadan kaldıran ve eski nesnelerin GC ihtiyacını ortadan kaldıran nesneleri geri dönüştürmek / yeniden kullanmak için bir havuz oluşturabilirsiniz.
Böyle bir şey (denenmemiş). Eğer iş parçacığı güvenli olmasını istiyorsanız, bir ConcurrentLinkedQueue için LinkedList takas edebilirsiniz.
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
G1 GC'li OracleJDK 10'da, tek bir çağrı System.gc()
GC'nin Eski Koleksiyonu temizlemesine neden olur. GC'nin hemen çalışıp çalışmadığından emin değilim. Bununla birlikte, GC, System.gc()
bir döngüde birçok kez çağrılsa bile, Genç Koleksiyonu temizlemeyecektir . GC'nin Genç Koleksiyonu temizlemesini sağlamak için new byte[1024]
aramadan bir döngüye (örn. ) Tahsis etmeniz gerekir System.gc()
. System.gc()
Bir sebepten ötürü aramak GC'nin Genç Koleksiyonu temizlemesini önler.
Gerçekten, seni anlamıyorum. Ama "Sonsuz Nesne Oluşturma" hakkında net olmak gerekirse, benim büyük sistemde bir parça kod var demek istediğini ve bellekte yaşayan nesneler oluşturma, aslında bu kod parçası alamadım, sadece jest !!
Bu doğru, sadece jest. Zaten birkaç afiş tarafından verilen standart cevaplara sahipsiniz. Bunu birer birer alalım:
Doğru, gerçek jvm yoktur - bu sadece bir şartname, istenen bir davranışı tanımlayan bilgisayar bilimi bir grup ... Son zamanlarda Java kodlarını yerel koddan başlatma içine kazdık. İstediğinizi elde etmek için tek yol agresif sıfırlama olarak adlandırılan şeyi yapmaktır. Yanlış yapıldığında yapılan hatalar o kadar kötü ki kendimizi sorunun orijinal kapsamıyla sınırlamalıyız:
Buradaki posterlerin çoğu, bir arayüzde çalıştığınızı söylediğinizi varsayacaktır, eğer böyle olursa, tüm nesneyi mi yoksa bir kerede bir öğeyi mi teslim aldığınızı görmek zorunda kalacağız.
Artık bir nesneye ihtiyacınız yoksa, nesneye null atayabilirsiniz, ancak yanlış alırsanız bir boş işaretçi istisnası oluşturulur. Eminim NIO kullanırsanız daha iyi işler başarabilirsiniz
Siz veya ben ya da herhangi bir kişi: " Lütfen buna çok ihtiyacım var. " Üzerinde çalışmaya çalıştığınız şeyin neredeyse tamamen yok edilmesinin neredeyse evrensel öncüsüdür .... bize herhangi bir dezenfekte ederek küçük bir örnek kod yazın gerçek kod kullanılır ve bize sorunuzu gösterir.
Sinirli olmayın. Çoğu zaman bunun çözdüğü şey, dba'nızın bir yere satın alınmış bir paket kullanması ve orijinal tasarımın büyük veri yapıları için ayarlanmamış olmasıdır.
Bu çok yaygın.
Bilginize
System.runFinalizersOnExit (true) yöntemi, Java kapatılmadan önce sonlandırıcı yöntemlerinin çağrılmasını garanti eder. Ancak, bu yöntem doğal olarak güvensizdir ve kullanımdan kaldırılmıştır. Alternatif olarak Runtime.addShutdownHook yöntemiyle “kapatma kancaları” eklemektir.
Masarrat Siddiqui
Çöp toplayıcıyı zorlamanın dolaylı bir yolu var. Çöp toplayıcının çalışacağı noktaya kadar yığını geçici nesnelerle doldurmanız yeterlidir. Çöp toplayıcıyı bu şekilde zorlayan bir sınıf yaptım:
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
Kullanımı:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
Ben sürekli yığın doldurur çünkü bu yöntem yararlıdır ne kadar bilmiyorum ama kritik uygulamanız varsa GEREKİR GC zorlamak - Bu GC zorlamak için Java taşınabilir bir yol olabilir zaman.
Buraya bir şeyler eklemek istiyorum. Java'nın gerçek Makine üzerinde değil Sanal Makine üzerinde çalıştığını lütfen unutmayın. Sanal makine, makine ile kendi iletişim yoluna sahiptir. Sistemden sisteme değişebilir. Şimdi GC'yi aradığımızda, Java'nın Sanal Makinesinden Çöp Toplayıcısını çağırmasını istiyoruz.
Çöp Toplayıcı Sanal Makine ile olduğundan, orada bir temizleme yapmaya zorlayamayız. Bunun yerine, isteğimizi Çöp Toplayıcı ile sıraya koyuyoruz. Sanal Makineye bağlıdır, belirli bir süre sonra (bu genellikle sistemden sisteme değişebilir, genellikle JVM'ye ayrılan eşik belleği dolduğunda) gerçek makine alanı boşaltacaktır. : D
Aşağıdaki kod assertGC (...) yönteminden alınır. Belirsiz çöp toplayıcısını toplamaya zorlar.
List<byte[]> alloc = new ArrayList<byte[]>();
int size = 100000;
for (int i = 0; i < 50; i++) {
if (ref.get() == null) {
// Test succeeded! Week referenced object has been cleared by gc.
return;
}
try {
System.gc();
} catch (OutOfMemoryError error) {
// OK
}
try {
System.runFinalization();
} catch (OutOfMemoryError error) {
// OK
}
// Approach the jvm maximal allocatable memory threshold
try {
// Allocates memory.
alloc.add(new byte[size]);
// The amount of allocated memory is increased for the next iteration.
size = (int)(((double)size) * 1.3);
} catch (OutOfMemoryError error) {
// The amount of allocated memory is decreased for the next iteration.
size = size / 2;
}
try {
if (i % 3 == 0) Thread.sleep(321);
} catch (InterruptedException t) {
// ignore
}
}
// Test failed!
// Free resources required for testing
alloc = null;
// Try to find out who holds the reference.
String str = null;
try {
str = findRefsFromRoot(ref.get(), rootsHint);
} catch (Exception e) {
throw new AssertionFailedErrorException(e);
} catch (OutOfMemoryError err) {
// OK
}
fail(text + ":\n" + str);
Kaynak (Netlik için bazı yorumlar ekledim): NbTestCase Örneği
Runtime.getRuntime().gc()
Yardımcı program yöntemini kullanmayı veya kullanmayı deneyebilirsiniz System.gc()
Not: Bu yöntemler GC'yi sağlamaz. Ve kapsamları, uygulamanızda programlı olarak kullanmak yerine JVM ile sınırlı olmalıdır.