Apakah mungkin untuk memaksa pengumpulan sampah di Jawa, bahkan jika itu sulit dilakukan? Saya tahu System.gc();
dan Runtime.gc();
tetapi mereka hanya menyarankan untuk melakukan GC. Bagaimana saya bisa memaksakan GC?
Apakah mungkin untuk memaksa pengumpulan sampah di Jawa, bahkan jika itu sulit dilakukan? Saya tahu System.gc();
dan Runtime.gc();
tetapi mereka hanya menyarankan untuk melakukan GC. Bagaimana saya bisa memaksakan GC?
Jawaban:
Pilihan terbaik Anda adalah menelepon System.gc()
yang hanya merupakan petunjuk bagi pengumpul sampah yang Anda inginkan untuk melakukan pengumpulan. Tidak ada cara untuk memaksa dan mengumpulkan segera karena pemulung tidak menentukan.
non-deterministic == trouble
GC.Collect()
tidak mengumpulkan. Di Jawa gc()
tidak.
The jlibs perpustakaan memiliki kelas utilitas yang baik untuk pengumpulan sampah . Anda dapat memaksa pengumpulan sampah menggunakan sedikit trik bagus dengan objek WeakReference .
RuntimeUtil.gc () dari jlibs:
/**
* 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
dengan ReferenceQueue
dan kemudian Anda akan diberi tahu setelah finalisasi, tetapi masih sebelum pembersihan. Akhirnya, bahkan jika Anda berhasil mendeteksi bahwa memori untuk objek ini direklamasi, itu masih berarti sangat sedikit dalam GC generasi seperti HotSpot. Biasanya itu akan bertepatan dengan pembersihan generasi muda.
System.gc(); System.gc();
, tetapi tentu akan menarik untuk mengetahui apakah itu pernah bekerja lebih baik dari itu. Bahkan, hanya mencetak berapa kali disebut System.gc()
sudah cukup. Peluang untuk mencapai 2 cukup tipis.
Cara terbaik (jika tidak hanya) untuk memaksa GC adalah dengan menulis JVM khusus. Saya percaya para pengumpul Sampah bisa dicolokkan sehingga Anda mungkin bisa memilih salah satu implementasi yang tersedia dan mengubahnya.
Catatan: Ini BUKAN jawaban yang mudah.
Menggunakan Java ™ Virtual Machine Tool Interface (JVM TI) , fungsinya
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
akan "Memaksa VM untuk melakukan pengumpulan sampah." JVM TI adalah bagian dari Platform Java Debugger Architecture (JPDA) .
YA hampir mungkin memaksa Anda harus memanggil metode dengan urutan yang sama dan pada saat yang sama ini adalah:
System.gc ();
System.runFinalization ();
bahkan jika hanya satu objek untuk membersihkan penggunaan kedua metode ini pada saat yang sama memaksa pemulung untuk menggunakan finalise()
metode objek yang tidak terjangkau membebaskan memori yang ditugaskan dan melakukan apa yang finalize()
dinyatakan oleh metode.
NAMUN merupakan praktik yang mengerikan untuk menggunakan pengumpul sampah karena penggunaannya dapat memperkenalkan kelebihan beban ke perangkat lunak yang mungkin bahkan lebih buruk daripada pada memori, pengumpul sampah memiliki utas sendiri yang tidak mungkin untuk dikontrol plus tergantung pada algoritma yang digunakan oleh gc bisa memakan waktu lebih lama dan dianggap sangat tidak efisien, Anda harus memeriksa perangkat lunak Anda jika terburuk dengan bantuan gc karena sudah pasti rusak, solusi yang baik tidak boleh bergantung pada gc.
CATATAN: hanya untuk diingat ini hanya akan berfungsi jika dalam metode finalisasi bukan penugasan kembali objek, jika ini terjadi objek akan tetap hidup dan akan memiliki kebangkitan yang secara teknis memungkinkan.
gc()
hanya isyarat untuk menjalankan pengumpulan sampah. runFinalizers()
hanya menjalankan finalizer pada objek "yang telah ditemukan dibuang". Jika gc tidak benar-benar berjalan, mungkin tidak ada objek seperti itu ...
Di bawah dokumentasi untuk OutOfMemoryError ia menyatakan bahwa itu tidak akan dibuang kecuali VM telah gagal untuk mendapatkan kembali memori setelah pengumpulan sampah penuh. Jadi, jika Anda terus mengalokasikan memori hingga Anda mendapatkan kesalahan, Anda sudah akan terpaksa mengumpulkan sampah penuh.
Mungkin pertanyaan yang benar-benar ingin Anda tanyakan adalah "bagaimana saya bisa mendapatkan kembali memori yang saya pikir saya harus reklamasi dengan pengumpulan sampah?"
Untuk Meminta GC secara manual (bukan dari System.gc ()):
.gc adalah kandidat untuk eliminasi dalam rilis mendatang - Insinyur Sun pernah berkomentar bahwa mungkin kurang dari dua puluh orang di dunia yang benar-benar tahu cara menggunakan .gc () - Saya melakukan pekerjaan tadi malam selama beberapa jam di pusat / kritis struktur data menggunakan data yang dihasilkan SecureRandom, di suatu tempat hanya melewati 40.000 objek vm akan melambat seolah-olah kehabisan pointer. Jelas itu tersedak tabel pointer 16-bit dan menunjukkan perilaku "mesin gagal" klasik.
Saya mencoba -Xms dan seterusnya, terus sedikit memutar-mutar sampai berjalan sekitar 57, xxx sesuatu. Maka itu akan menjalankan gc dari mengatakan 57.127 menjadi 57.128 setelah gc () - sekitar kecepatan code-bloat di camp Easy Money.
Desain Anda perlu dikerjakan ulang secara mendasar, mungkin pendekatan jendela geser.
Anda dapat memicu GC dari baris perintah. Ini berguna untuk batch / crontab:
jdk1.7.0/bin/jcmd <pid> GC.run
Lihat :
Spesifikasi JVM tidak mengatakan sesuatu yang spesifik tentang pengumpulan sampah. Karena itu, vendor bebas menerapkan GC dengan cara mereka.
Jadi ketidakjelasan ini menyebabkan ketidakpastian dalam perilaku pengumpulan sampah. Anda harus memeriksa detail JVM Anda untuk mengetahui tentang pendekatan / algoritma pengumpulan sampah. Juga ada opsi untuk menyesuaikan perilaku.
Jika Anda perlu memaksakan pengumpulan sampah, mungkin Anda harus mempertimbangkan bagaimana Anda mengelola sumber daya. Apakah Anda membuat objek besar yang bertahan dalam memori? Apakah Anda membuat objek besar (misalnya, kelas grafis) yang memiliki Disposable
antarmuka dan tidak memanggil dispose()
ketika selesai dengannya? Apakah Anda mendeklarasikan sesuatu di tingkat kelas yang hanya Anda perlukan dalam satu metode?
Akan lebih baik jika Anda menjelaskan alasan mengapa Anda membutuhkan pengumpulan sampah. Jika Anda menggunakan SWT, Anda dapat membuang sumber daya seperti Image
dan Font
untuk membebaskan memori. Misalnya:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
Ada juga alat untuk menentukan sumber daya yang tidak diinginkan.
Jika Anda kehabisan memori dan mendapatkan yang OutOfMemoryException
Anda dapat mencoba meningkatkan jumlah ruang tumpukan yang tersedia untuk java dengan memulai program Anda dengan java -Xms128m -Xmx512m
bukan hanya java
. Ini akan memberi Anda ukuran tumpukan awal 128Mb dan maksimum 512Mb, yang jauh lebih dari standar 32Mb / 128Mb.
java -Xms512M -Xmx1024M
Pilihan lain adalah tidak membuat objek baru.
Penyatuan objek jauh untuk mengurangi kebutuhan GC di Jawa.
Pengumpulan objek umumnya tidak akan lebih cepat dari Pembuatan objek (terutama untuk objek ringan) tetapi lebih cepat dari Pengumpulan Sampah. Jika Anda membuat 10.000 objek dan setiap objek adalah 16 byte. 160.000 byte GC harus diperoleh kembali. Di sisi lain, jika Anda tidak membutuhkan semua 10.000 pada saat yang sama, Anda dapat membuat kumpulan untuk mendaur ulang / menggunakan kembali objek yang menghilangkan kebutuhan untuk membangun objek baru dan menghilangkan kebutuhan untuk GC objek lama.
Sesuatu seperti ini (belum diuji). Dan jika Anda menginginkannya aman, Anda dapat menukar keluar LinkedList dengan ConcurrentLinkedQueue.
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) { }
}
Pada OracleJDK 10 dengan G1 GC, satu panggilan ke System.gc()
akan menyebabkan GC membersihkan Koleksi Lama. Saya tidak yakin apakah GC langsung berjalan. Namun, GC tidak akan membersihkan Young Collection bahkan jika System.gc()
dipanggil berkali-kali dalam satu lingkaran. Untuk mendapatkan GC untuk membersihkan Koleksi Muda, Anda harus mengalokasikan dalam satu lingkaran (mis. new byte[1024]
) Tanpa menelepon System.gc()
. Menelepon System.gc()
untuk beberapa alasan mencegah GC dari membersihkan Young Collection.
Sungguh, saya tidak mengerti Anda. Tetapi untuk memperjelas "Penciptaan Objek Tak Terbatas" yang saya maksudkan adalah ada beberapa kode di sistem besar saya yang membuat objek yang menangani dan hidup dalam memori, saya tidak bisa mendapatkan kode ini sebenarnya, hanya isyarat !!
Ini benar, hanya isyarat. Anda memiliki cukup banyak jawaban standar yang sudah diberikan oleh beberapa poster. Mari kita ambil satu per satu ini:
Benar, tidak ada jvm yang sebenarnya - hanya ada spesifikasi, sekelompok ilmu komputer yang menggambarkan perilaku yang diinginkan ... Saya baru saja menggali untuk menginisialisasi objek Java dari kode asli. Untuk mendapatkan apa yang Anda inginkan, satu-satunya cara adalah melakukan apa yang disebut agresif nulling. Kesalahan jika dilakukan salah begitu buruk sehingga kita harus membatasi diri pada lingkup asli dari pertanyaan:
Sebagian besar poster di sini akan menganggap Anda mengatakan Anda bekerja pada sebuah antarmuka, jika demikian kami harus melihat apakah Anda sedang menyerahkan seluruh objek atau satu item pada suatu waktu.
Jika Anda tidak lagi membutuhkan objek, Anda dapat menetapkan null ke objek tetapi jika Anda salah ada pengecualian null pointer yang dihasilkan. Saya yakin Anda dapat mencapai pekerjaan yang lebih baik jika Anda menggunakan NIO
Setiap kali Anda atau saya atau orang lain mendapatkan: " Tolong saya sangat membutuhkannya. " Ini hampir merupakan prekursor universal untuk kehancuran total yang hampir sama dengan apa yang Anda coba kerjakan .... tulis kami kode sampel kecil, bersihkan dari apa pun kode aktual yang digunakan dan tunjukkan pertanyaan Anda kepada kami.
Jangan frustrasi. Seringkali apa yang dipecahkan adalah dBA Anda menggunakan paket yang dibeli di suatu tempat dan desain aslinya tidak diubah untuk struktur data yang besar.
Itu sangat umum.
FYI
Pemanggilan metode System.runFinalizersOnExit (true) menjamin bahwa metode finalizer dipanggil sebelum Java dimatikan. Namun, metode ini secara inheren tidak aman dan telah usang. Alternatifnya adalah menambahkan "shutdown hooks" dengan metode Runtime.addShutdownHook.
Masarrat Siddiqui
Ada beberapa cara tidak langsung untuk memaksa pemulung. Anda hanya perlu mengisi tumpukan dengan benda-benda sementara sampai titik ketika pengumpul sampah akan mengeksekusi. Saya telah membuat kelas yang memaksa pemulung dengan cara ini:
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;
}
}
Pemakaian:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
Saya tidak tahu berapa banyak metode ini berguna, karena mengisi tumpukan terus-menerus, tetapi jika Anda memiliki aplikasi misi kritis yang HARUS memaksa GC - saat ini mungkin cara portabel Java untuk memaksa GC.
Saya ingin menambahkan sesuatu di sini. Tolong bukan bahwa Java berjalan pada Mesin Virtual dan bukan Mesin yang sebenarnya. Mesin virtual memiliki cara komunikasi sendiri dengan mesin. Ini mungkin bervariasi dari satu sistem ke sistem lainnya. Sekarang Ketika kita memanggil GC kita meminta Mesin Virtual Java untuk memanggil Pengumpul Sampah.
Karena Pengumpul Sampah menggunakan Mesin Virtual, kami tidak dapat memaksanya melakukan pembersihan di sana dan kemudian. Sebaliknya, kami mengantri permintaan kami dengan Pengumpul Sampah. Itu tergantung pada Mesin Virtual, setelah waktu tertentu (ini dapat berubah dari sistem ke sistem, umumnya ketika ambang memori yang dialokasikan untuk JVM penuh) mesin yang sebenarnya akan membebaskan ruang. : D
Kode berikut diambil dari metode assertGC (...). Ini mencoba untuk memaksa pengumpul sampah nondeterministic untuk mengumpulkan.
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);
Sumber (saya menambahkan beberapa komentar untuk kejelasan): Contoh NbTestCase
Anda dapat mencoba menggunakan Runtime.getRuntime().gc()
atau menggunakan metode utilitas System.gc()
Catatan: Metode ini tidak memastikan GC. Dan ruang lingkup mereka harus dibatasi pada JVM daripada secara terprogram menangani aplikasi Anda.