Diagram struktur internal JVM
Mesin virtual Java terutama dibagi menjadi lima area: area metode, tumpukan, tumpukan java, register PC, dan tumpukan metode lokal. Mari kita lihat beberapa masalah penting tentang struktur JVM.
1. Area mana yang dibagikan? Mana yang pribadi?
Tumpukan Java, Stack Metode Lokal, dan Penghitung Program ditetapkan dan dihancurkan saat utas pengguna dimulai dan berakhir.
Setiap utas memiliki area independen ini. Area metode dan tumpukan dibagikan oleh semua utas di seluruh proses JVM.
2. Apa yang disimpan di area metode? Apakah itu akan didaur ulang?
Area metode ini tidak hanya informasi dan kode metode yang disimpan. Pada saat yang sama, di sub-wilayah yang disebut runtime constant pool, berbagai referensi simbolik dalam tabel konstan dalam file kelas, serta referensi langsung yang diterjemahkan. Informasi ini diakses melalui objek kelas di tumpukan sebagai antarmuka.
Meskipun informasi jenis disimpan di area metode, itu juga akan didaur ulang, tetapi kondisi daur ulang relatif ketat:
(1) Semua contoh kelas ini telah didaur ulang
(2) ClassLoader Memuat kelas ini telah didaur ulang
(3) Objek kelas kelas ini tidak dirujuk di mana pun (termasuk kelas. Akses Refleksi Forname)
3. Apakah kandungan kumpulan konstan di area metode tidak berubah?
Kumpulan konstan runtime di area metode menyimpan data di kumpulan konstan statis di file kelas. Selain menyimpan berbagai referensi literal dan simbolis yang dihasilkan pada waktu kompilasi, itu juga berisi referensi langsung yang diterjemahkan. Tetapi ini tidak berarti bahwa kumpulan konstan tidak akan berubah selama runtime. Misalnya, saat berjalan, Anda dapat memanggil metode magang string dan memasukkan konstanta string baru ke dalam kumpulan.
paket com.cdai.jvm; kelas publik runtimeconstantpool {public static void main (string [] args) {string s1 = string baru ("hello"); String s2 = string baru ("halo"); System.out.println ("Sebelum magang, S1 == S2:" + (S1 == S2)); S1 = S1.Intern (); s2 = s2.intern (); System.out.println ("Setelah magang, S1 == S2:" + (S1 == S2)); }}
4. Apakah semua instance objek dialokasikan pada tumpukan?
Dengan kematangan bertahap dari teknologi analisis melarikan diri, alokasi di atas dan teknologi optimasi penggantian skalar telah membuat "semua objek yang dialokasikan pada tumpukan" kurang absolut.
Yang disebut pelarian berarti bahwa ketika pointer objek dirujuk oleh banyak metode atau utas, kami mengatakan bahwa pointer ini melarikan diri.
Secara umum, objek Java dialokasikan di tumpukan, dan hanya petunjuk objek yang disimpan di tumpukan. Dengan asumsi bahwa variabel lokal tidak lepas selama pelaksanaan metode (terpapar ke luar metode), itu akan dialokasikan langsung pada tumpukan dan kemudian terus dieksekusi dalam tumpukan panggilan. Setelah pelaksanaan metode, ruang tumpukan didaur ulang dan variabel lokal juga didaur ulang. Ini mengurangi alokasi sejumlah besar objek sementara di tumpukan dan meningkatkan efisiensi daur ulang GC.
Selain itu, analisis pelarian juga akan menghilangkan kunci pada variabel lokal yang belum melarikan diri, dan menghilangkan kunci yang dimiliki pada variabel ini.
Saat mengaktifkan metode analisis pelarian, tambahkan parameter startup JVM: -xx: +doDcapeanalysis? Escapeanysistest.
5. Berapa banyak cara untuk mengakses objek di tumpukan?
(1) Akses langsung ke penunjuk
Referensi pada tumpukan menyimpan pointer ke objek di tumpukan, dan Anda dapat menemukan objek dalam sekali jalan, yang memiliki kecepatan akses yang lebih cepat.
Namun, ketika objek dipindahkan dalam tumpukan (setiap objek sering dipindahkan selama pengumpulan sampah), nilai variabel pointer pada tumpukan juga perlu diubah. Saat ini, JVM Hotspot mengadopsi metode ini.
(2) Akses tidak langsung ke pegangan
Referensi pada titik tumpukan ke pegangan di kumpulan pegangan, dan objek diakses melalui nilai dalam pegangan ini. Oleh karena itu, pegangannya seperti penunjuk sekunder, yang membutuhkan dua posisi untuk mengakses objek, yang lebih lambat dari posisi penunjuk langsung, tetapi ketika objek bergerak di tumpukan, tidak perlu mengubah nilai yang dirujuk pada tumpukan.
Bagaimana melimpah jvm
Setelah memahami peran lima bidang memori mesin virtual Java, mari kita terus belajar dalam keadaan apa area ini akan meluap.
1. Konfigurasi Parameter Mesin Virtual
-Xms: Ukuran tumpukan awal, default adalah 1/64 dari memori fisik (<1GB); Default (parameter MinHeapFreeratio dapat disesuaikan) ketika memori tumpukan bebas kurang dari 40%, JVM akan meningkatkan heap hingga batas maksimum -xmx.
-Xmx: Ukuran tumpukan maksimum, default (parameter maxheapFreeratio dapat disesuaikan) ketika memori heap bebas lebih besar dari 70%, JVM akan mengurangi tumpukan hingga batas minimum -xms.
-XSS: Ukuran tumpukan untuk setiap utas. Setelah JDK5.0, ukuran tumpukan masing -masing utas adalah 1m, dan di masa lalu, ukuran tumpukan masing -masing utas adalah 256K. Itu harus disesuaikan dengan tepat sesuai dengan ukuran memori yang diperlukan dari utas aplikasi. Dalam memori fisik yang sama, mengurangi nilai ini dapat menghasilkan lebih banyak utas. Namun, sistem operasi masih memiliki batas pada jumlah utas dalam suatu proses dan tidak dapat dihasilkan secara tak terbatas, dengan nilai pengalaman mulai dari sekitar 3000 hingga 5.000. Umumnya, aplikasi kecil, jika tumpukan tidak terlalu dalam, 128k seharusnya cukup. Untuk aplikasi besar, 256K direkomendasikan. Opsi ini memiliki dampak besar pada kinerja dan membutuhkan pengujian yang ketat.
-Xx: Permsize: Tetapkan nilai awal generasi permanen (perm gen). Nilai default adalah 1/64 dari memori fisik.
-XX: MAXPERMSIZE: Atur nilai maksimum generasi persisten. 1/4 memori fisik.
2. Metode area meluap
Karena area metode menyimpan informasi yang relevan dari kelas, ketika kami memuat terlalu banyak kelas, area metode akan meluap. Di sini kami mencoba meluap area metode melalui dua metode: JDK Dynamic Proxy dan CGLIB Proxy.
2.1 JDK Dynamic Proxy
paket com.cdai.jvm.overflow; impor java.lang.reflect.invocationHandler; impor java.lang.reflect.method; impor java.lang.reflect.proxy; Kelas publik MethodareaOverflow {statis antarmuka oomiinterface {} kelas statis oomObject mengimplementasikan oomiinterface {} kelas statis oomobject2 mengimplementasikan oomiinterface {} public static void main (string [] args) {final oomobject objek = oomobject baru (); while (true) {oomiinterface proxy = (oomiinterface) proxy.newproxyInstance (thread.currentThread (). getContextClassLoader (), oomobject.class.getInterfaces (), new doubokholdhandler () {@override Object Public Procoke (Object PROX () {@override Public Proxy (), Objok {Objek) {@override public proxy () { @eMPOBLED () { @eMOBIDSED () {@OMOBIDED (), Objek Objek (), Objek Objek (), Objek Objek (), Object Ombect () System.out.println ("Interceptor1 bekerja"); System.out.println (proxy.getClass ()); System.out.println ("Proxy1:" + Proxy); Oomiinterface proxy2 = (oomiinterface) proxy.newProxyInstance (thread.currentThread (). GetContextClassLoader (), oomobject.class.getInterfaces (), Metode InvocationHandler () {@override Objek publik Incoke (Object Proxy, Metode Metode, Metode, Metode, Metode, Metode Objek, Metode Objek, Metode Objek, Metode Objok, Metode Objek, Metode Objok, Metode Objok, System.out.println ("Interceptor2 bekerja"); System.out.println (proxy2.getClass ()); System.out.println ("Proxy2:" + Proxy2); }}} Meskipun kami terus memanggil metode proxy.newinstance () untuk membuat kelas proxy, JVM tidak memiliki overflow memori.
Setiap panggilan menghasilkan contoh yang berbeda dari kelas proxy, tetapi objek kelas kelas proxy tidak berubah. Apakah itu proxy
Apakah kelas memiliki cache untuk objek kelas kelas proxy? Alasan spesifik akan dianalisis secara rinci dalam "JDK Dynamic Proxy dan CGLIB" berikutnya.
2.2 Agen CGLIB
CGLIB juga akan menyimpan objek kelas dari kelas proxy, tetapi kami dapat mengkonfigurasinya untuk tidak menemui objek kelas.
Dengan cara ini, tujuan meluapnya area metode dapat dicapai dengan berulang kali membuat kelas proxy.
paket com.cdai.jvm.overflow; impor java.lang.reflect.method; impor net.sf.cglib.proxy.enhancer; impor net.sf.cglib.proxy.methodInterceptor; impor net.sf.cglib.proxy.methodproxy; kelas publik MethodareAverFlow2 {kelas statis oomObject {} public static void main (string [] args) {while (true) {Enhancer Enhancer = new Enhancer (); Enhancer.setsuperclass (oomobject.class); Enhancer.setusecache (false); Enhancer.setCallback (MethodInterceptor baru () {@Override Public Object Intercept (objek OBJ, metode metode, objek [] args, MethodProxy Proxy) melempar Throwable {return method.invoke (OBJ, args);}}); Oomobject proxy = (oomObject) Enhancer.create (); System.out.println (proxy.getClass ()); }}}
3. HEAP OVERFLOW
Tumpukan luapan relatif sederhana. Anda dapat melimpah tumpukan dengan membuat objek array besar.
paket com.cdai.jvm.overflow; kelas publik heapoverflow {private static final int mb = 1024 * 1024; @SuppressWarnings ("tidak digunakan") public static void main (string [] args) {byte [] BigMemory = byte baru [1024 * mb]; }}
4. Stack overflow
Stack overflow juga umum. Kadang -kadang ketika panggilan rekursif yang kami tulis tidak memiliki kondisi penghentian yang benar, metode ini akan terus berulang, kedalaman tumpukan akan terus meningkat, dan pada akhirnya tumpukan overflow akan terjadi.
paket com.cdai.jvm.overflow; kelas publik stackoverflow {private static int stackdepth = 1; public static void stackoverflow () {stackdepth ++; stackoverflow (); } public static void main (string [] args) {coba {stackoverflow (); } catch (Exception e) {System.err.println ("Stack Depth:" + StackDepth); e.printstacktrace (); }}}