Tumpukan Java digunakan untuk menyimpan instance objek. Oleh karena itu, jika kita terus membuat objek dan memastikan bahwa ada jalur yang dapat diakses antara akar GC dan objek yang dibuat untuk menghindari objek yang dikumpulkan sampah, maka ketika terlalu banyak objek dibuat, itu akan menyebabkan memori heap yang tidak mencukupi, yang akan meningkatkan pengecualian outofmemoryError.
/** * @author xionggyongshun * vm args: java -xms10m -xmx10m -xx:+heapdumponoutofmemoryError */kelas publik outofmemoryErrortest {public static void main (string [] args) {list <integer> list = new arraylist <> (> (] args) {list <Integer> list = new arraylist <> (> (string) {list <Integer> list = new arraylist <> (> (string) {list <Integer> list = new arraylist <> (> (> args) {list <Integer> list = new arraylist <> (> (string); int i = 0; while (true) {list.add (i ++); }}}Di atas adalah kode yang menaikkan pengecualian outofmemoryError. Kita dapat melihat bahwa itu mencegah objek menjadi sampah yang dikumpulkan dengan terus -menerus membuat dan menyimpan objek dalam daftar. Oleh karena itu, ketika ada terlalu banyak objek, memori tumpukan akan meluap.
Melalui java -xms10m -xmx10m -xx:+heapdumponoutofmemoryError, kami mengatur memori heap ke 10 megabytes, dan menggunakan parameter -xx:+heapdumponoutofmemoryError untuk membuat jvm cetak snapshot saat ini.
Setelah menyusun dan menjalankan kode di atas, output berikut adalah:
>>> java -xms10m -xmx10m -xx:+heapdumponoutofmemoryError com.test.outofmemoryerrortest 16-10-02 23: 35java.lang.outofmemoryError: java heap heap heap heap heap untuk java_pid1818.hpof12 0.125 detik] Pengecualian di Thread "Main" Java.lang.outofmemoryError: Java Heap Space di java.util.arrays.copyof (arrays.java:3210) di java.util.arrays.copyof (arrays.java:3181) di java.util. java.util.arraylist.ensureexplicitcapacity (arraylist.java:235) di java.util.arraylist.ensurecapityinternal (arraylist.java:227) di java.util.arraylist.add (arraylist.java:4) atraylist.add (arraylist.java:4) com.test.outofmemoryerrortest.main (outofmemoryerrortest.java:15)
Java Stackoverflowerror
Kita tahu bahwa ada area memori yang disebut tumpukan mesin virtual di area data runtime JVM. Fungsi area ini adalah: setiap metode akan membuat bingkai tumpukan saat dieksekusi, yang digunakan untuk menyimpan informasi seperti tabel variabel lokal, tumpukan operan, keluar metode, dll.
Oleh karena itu, kita dapat membuat panggilan rekursif rekursif yang tak terbatas. Ketika kedalaman rekursif terlalu besar, ruang tumpukan akan habis, yang akan menyebabkan pengecualian stackoverflowerror.
Ini kode spesifiknya:
/** * @author xionggyongshun * vm args: java -xss64k */kelas publik outofmemoryErrortest {public static void main (string [] args) {stackoutofmemoryError (1); } public static void stackoutOfMemoryError (int kedalaman) {kedalaman ++; StackoutOfMemoryError (kedalaman); }}Setelah menyusun dan menjalankan kode di atas, informasi pengecualian berikut akan menjadi output:
Pengecualian di Thread "Main" Java.lang.Stackoverflowerror di com.test.outofmemoryerrortest.stackoutofmemoryError (outofmemoryerrortest.java:27)
Memori overflow di area metode
Perhatikan bahwa karena JDK8 telah menghapus generasi permanen dan menggantinya dengan Metaspace, di JDK8, tak satu pun dari dua contoh berikut akan menyebabkan java.lang.outofmemoryError: Permgen Space Exception.
Pool yang konstan meluap selama runtime
Dalam Java 1.6 dan versi hotspot JVM sebelumnya, ada konsep generasi permanen, yaitu, mekanisme pengumpulan generasi GC diperluas ke area metode. Di area metode, bagian dari memori digunakan untuk menyimpan kolam konstan. Oleh karena itu, jika ada terlalu banyak konstanta dalam kode, memori kumpulan konstan akan habis, menghasilkan overflow memori. Jadi bagaimana cara menambahkan sejumlah besar konstanta ke kolam konstan? Pada saat ini, Anda harus mengandalkan metode String.Intern (). Fungsi metode string.intern () adalah: Jika nilai string ini sudah ada di kumpulan konstan, metode ini mengembalikan referensi ke string yang sesuai di kumpulan konstan; Jika tidak, tambahkan nilai yang terkandung dalam string ini ke kumpulan konstan dan kembalikan referensi ke objek string ini. Dalam JDK 1.6 dan versi sebelumnya, kumpulan konstan dialokasikan dalam generasi permanen. Oleh karena itu, kita secara tidak langsung dapat membatasi ukuran kumpulan konstan dengan mengatur parameter "-xx: permsize" dan "-xx: maxpermsize".
Perhatikan bahwa distribusi memori dari string.intern () metode yang disebutkan di atas dan kumpulan konstan hanya untuk JDK 1.6 dan versi sebelumnya. Dalam JDK 1.7 atau lebih, tata letak memori sedikit berbeda karena konsep generasi permanen dihapus.
Berikut ini adalah contoh kode untuk mengimplementasikan overflow memori kumpulan konstan:
/** * @Author xionggyongshun * vm args: -xx: permsize = 10m -xx: maxpermsize = 10m */kelas publik runtimeconstantpooloomtest {public static void main (string [] args) {list <string> list = new arraylist <string> (); int i = 0; while (true) {list.add (string.valueof (i ++). magang ()); }}}Kita melihat bahwa dalam contoh ini, itu tepat menggunakan metode string.INNERN () untuk menambahkan sejumlah besar konstanta string ke kumpulan konstan, yang mengarah ke memori overflow kumpulan konstan.
Kami mengkompilasi dan menjalankan kode di atas melalui JDK1.6, dan output berikut adalah:
Pengecualian di Thread "Main" java.lang.outofmemoryError: Ruang Permgen di java.lang.string.intern (Metode Asli) di com.test.runtimeconstantpooloomtest.main (runtimeconstantpooloomtest.java:16)
Perlu dicatat bahwa jika kode di atas dikompilasi dan dijalankan melalui JDK1.8, akan ada peringatan berikut dan tidak ada pengecualian akan dihasilkan:
>>> java -xx: permsize = 10m -xx: maxpermsize = 10m com.test.runtimeconstantpooloomtest 16-10-03 0: 23java hotspot (TM) server 64-bit Peringatan VM: Mengabaikan opsi Permsize = 10m; Dukungan telah dihapus dalam 8.0 Java Hotspot (TM) Server 64-Bit Peringatan VM: Mengabaikan opsi MaxperMSize = 10m; Dukungan telah dihapus di 8.0
Meluap memori di area metode
Fungsi dari area metode adalah untuk menyimpan informasi yang relevan dari kelas, seperti nama kelas, pengubah akses kelas, deskripsi lapangan, deskripsi metode, dll. Oleh karena itu, jika area metode terlalu kecil dan terlalu banyak kelas dimuat, meluap memori dari area metode.
// VM args: -xx: Permsize = 10m -xx: maxpermsize = 10MPublic class MethodAeAomtest {public static void main (string [] args) {while (true) {Enhancer Enhancer = new Enhancer (); Enhancer.setsuperclass (MethodareAomtest.class); Enhancer.setusecache (false); Enhancer.setCallback (MethodInterceptor baru () {Public Object Intercept (Object O, Metode Metode, Objek [] Objek, MethodProxy MethodProxy) melempar Throwable {return methodproxy.invokeSuper (O, Objects);}}); Enhancer.create (); }}}Dalam kode di atas, kami menggunakan CGLIB untuk secara dinamis menghasilkan sejumlah besar kelas. Di JDK6, menjalankan kode di atas akan menghasilkan outofmemoryError: Permgen Space Exception:
/System/library/frameworks/javm.framework/versions/1.6/home/bin/java -jar -xx: permsize = 10m -xx: maxpermsize = 10m target/test -.0-snapshot.jar
Hasil output adalah sebagai berikut:
Disebabkan oleh: java.lang.outofmemoryError: Permgen Space di java.lang.classloader.defineClass1 (metode asli) di java.lang.classloader.defineClasscond (classloader.java:637) di java.lang.classloader.defleer.def
Metaspace memori overflow
Di bagian memori memori memori memori di bidang metode, kami menyebutkan bahwa JDK8 tidak memiliki konsep generasi permanen, sehingga kedua contoh itu tidak mencapai efek yang diharapkan di bawah JDK8. Jadi di JDK8, apakah ada kesalahan seperti meluap memori di area metode? Tentu saja, beberapa. Di JDK8, area Metaspace digunakan untuk menyimpan informasi terkait kelas, jadi ketika Metaspace tidak mencukupi, java.lang.outofmemoryError: Pengecualian Metaspace akan dilemparkan.
Mari kita ambil contoh yang disebutkan di atas sebagai contoh:
// vm args: -xx: maxmetaspacesize = 10mpublic class MethodareAoomTest {public static void main (string [] args) {while (true) {penambah penambah = penambah baru (); Enhancer.setsuperclass (MethodareAomtest.class); Enhancer.setusecache (false); Enhancer.setCallback (MethodInterceptor baru () {Public Object Intercept (Object O, Metode Metode, Objek [] Objek, MethodProxy MethodProxy) melempar Throwable {return methodproxy.invokeSuper (O, Objects);}}); Enhancer.create (); }}}Bagian kode dari contoh ini belum diubah. Satu -satunya perbedaan adalah bahwa kita perlu menggunakan JDK8 untuk menjalankan kode ini, dan mengatur parameter -xx: maxmetaspacesize = 10m. Parameter ini memberi tahu JVM bahwa ukuran maksimum Metaspace adalah 10m.
Kemudian kami menggunakan JDK8 untuk mengkompilasi dan menjalankan contoh ini, dan mengeluarkan pengecualian berikut:
>>> java -jar -xx: maxmetaspacessize = 10m target/test -1.0 -snapshot.jarexception di utas "utama" java.lang.outofmemoryError: metaspace di net.sf.cglib.core.abstractclassgenerator.generate (abstracationclassGenerator.cglib.core.abstractclassorator. net.sf.cglib.proxy.enhancer.generate (Enhancer.java:492) di net.sf.cglib.core.abstractclassgenerator $ classloaderData.get (abstractclassclasor.java:114) di net.sf.cglib.core.abstractclacor.java:114) di net.sf.cglib.core.abstractcract.java:114) di net.sf.cglib.core.abstractcract.java:114 di net.sf.cglib.proxy.enhancer.createhelper (Enhancer.java:480) di net.sf.cglib.proxy.enhancer.create (Enhancer.java:305) di com.test.methodareaoomtest.main (MethodareAeAoomtest.jest.joVest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.jest.
Meringkaskan
Di atas adalah semua tentang pengecualian overflow memori umum dan contoh kode dalam artikel ini, saya harap ini akan membantu semua orang. Teman yang tertarik dapat terus merujuk ke topik terkait lainnya di situs ini. Jika ada kekurangan, silakan tinggalkan pesan untuk menunjukkannya. Terima kasih teman atas dukungan Anda untuk situs ini!