Rumah > Java > javaTutorial > teks badan

Analisis kes masalah kebocoran memori Java

WBOY
Lepaskan: 2023-05-23 18:46:06
ke hadapan
962 orang telah melayarinya

Masalah kebocoran memori Java

Apa yang dipanggil kebocoran memori bermakna objek atau pembolehubah yang tidak lagi digunakan oleh program telah diduduki dalam ingatan.

Terdapat mekanisme pengumpulan sampah di Jawa, yang boleh memastikan apabila objek tidak lagi dirujuk, iaitu apabila objek menjadi anak yatim, objek itu akan dikosongkan secara automatik daripada ingatan oleh pengumpul sampah .

Memandangkan Java mempunyai mekanisme pengumpulan sampah, mengapa masih terdapat masalah kebocoran memori?

Tidak lebih daripada itu sesetengah objek tidak boleh diproses oleh pemungut sampah, menyebabkan objek ini menduduki memori JVM sepanjang masa, yang akan membawa kepada kebocoran memori.

Memandangkan Java menggunakan graf terarah untuk pengurusan pengumpulan sampah, ia boleh menghapuskan masalah kitaran rujukan Contohnya, jika terdapat dua objek yang merujuk antara satu sama lain, selagi ia tidak boleh diakses proses akar, maka GC juga akan Mereka boleh dikitar semula Sebagai contoh, kod berikut boleh melihat kitar semula memori dalam kes ini.

import java. io.IOException;
public class GarbageTest {

    public static void main(String[] args) throws IOException {
        try {
            // TODO Auto-generated method stub
            gcTest();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("has exited gcTest!");
        System.in.read();
        System.in.read();
        System.out.println("out begin gc!");
        for (int i = 0; i < 100; i++) {
            System.gc();
            System.in.read();
            System.in.read();
        }
    }

    private static void gcTest() throws IOException {
        System.in.read();
        System.in.read();
        Person p1 = new Person();
        System.in.read();
        System.in.read();
        Person p2 = new Person();
        p1.setMate(p2);
        p2.setMate(p1);
        System.out.println("before exit gctest!");
        System.in.read();
        System.in.read();
        System.gc();
        System.out.println("exit gctest!");
    }

    private static class Person {
        byte[] data = new byte[20000000];
        Person mate = null;

        public void setMate(Person other) {
            mate = other;
        }
    }

}
Salin selepas log masuk

Memori bocor di Jawa: Jika objek berumur panjang memegang rujukan kepada objek jangka pendek, kebocoran memori mungkin berlaku Walaupun objek jangka pendek tidak lagi diperlukan, kerana tahan lama Objek kitaran memegang rujukannya dan tidak boleh dikitar semula Ini adalah senario di mana kebocoran memori berlaku di Jawa Dalam istilah orang awam, pengaturcara boleh mencipta objek dan tidak menggunakannya lagi, tetapi objek itu sentiasa digunakan. Rujukan bermakna objek ini tidak berguna tetapi tidak boleh dikitar semula oleh pengumpul sampah Ini adalah situasi di mana kebocoran memori mungkin berlaku di Jawa.

Sebagai contoh, dalam sistem cache, kami memuatkan objek dan meletakkannya dalam cache (contohnya, dalam objek peta global), dan kemudian tidak menggunakannya lagi Nilai objek ini dirujuk oleh cache, tetapi ia tidak lagi digunakan dengan mudah.

Untuk menyemak kebocoran memori dalam Java, pastikan anda membenarkan program melaksanakan semua cawangan hingga akhir program, dan kemudian lihat jika objek telah digunakan, maka anda boleh menentukan objek tersebut adalah kebocoran ingatan.

Jika kaedah objek contoh kelas luar mengembalikan objek contoh kelas dalam, objek kelas dalam dirujuk untuk masa yang lama, walaupun objek contoh kelas luar tidak lagi digunakan, tetapi kerana kelas dalam kekal di luar objek Instance kelas, objek kelas luaran ini tidak akan dikumpul sampah, yang juga akan menyebabkan kebocoran memori.

Kandungan berikut datang daripada Internet (ciri utama adalah untuk mengosongkan elemen dalam timbunan, bukan untuk mengalih keluar sepenuhnya daripada tatasusunan, tetapi untuk mengurangkan jumlah yang disimpan. Saya boleh menulis lebih baik daripada ini, Apabila mengalih keluar elemen, juga hilangkan ia daripada tatasusunan, cuma tetapkan nilai kedudukan elemen itu kepada null)

Saya benar-benar tidak dapat memikirkan contoh yang lebih klasik daripada tindanan itu, jadi Kerana saya kena petik contoh orang lain, contoh berikut bukanlah apa yang saya fikirkan, tetapi apa yang saya lihat dalam buku sudah tentu, jika saya tidak melihatnya dalam buku, saya mungkin terfikir sendiri selepas beberapa ketika, tetapi pada masa itu saya berkata saya memikirkannya sendiri dan tiada siapa yang percaya.

public class Stack {
    private Object[] elements = new Object[10];
    private int size = 0;

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0) throw new EmptyStackException();
        return elements[--size];
    }

    private void ensureCapacity() {
        if (elements.length == size) {
            Object[] oldElements = elements;
            elements = new Object[2 * elements.length + 1];
            System.arraycopy(oldElements, 0, elements, 0, size);
        }
    }
}
Salin selepas log masuk

Prinsip di atas sepatutnya sangat mudah Jika 10 elemen ditambah ke dalam timbunan wang, dan kemudian mereka semua muncul, walaupun timbunan wang kosong dan tiada apa yang kita mahu, objek ini tidak boleh. dikitar semula Ini memenuhi dua syarat kebocoran memori Ia tidak berguna dan tidak boleh dikitar semula. Tetapi jika perkara sebegini wujud, ia tidak semestinya membawa kepada apa-apa akibat Jika wang yang bertimbun ini digunakan kurang, ia hanya akan membazirkan beberapa K ingatan mempunyai? , Selain itu, perkara ini akan dikitar semula tidak lama lagi, jadi apa yang penting? Mari lihat dua contoh di bawah.

class Bad {
    public static Stack s = new Stack();
    static {
        s.push(new Object());

        s.pop(); //这里有一个对象发生内存泄露

        s.push(new Object());//上面的对象可以被回收了,等于是自愈了
    }
}
Salin selepas log masuk

Oleh kerana ia statik, ia akan wujud sehingga program keluar, tetapi kita juga dapat melihat bahawa ia mempunyai fungsi penyembuhan diri, yang bermaksud bahawa jika Stack anda mempunyai maksimum 100 objek, maka akan ada hanya maksimum 100 objek Ia tidak boleh dikitar semula, sebenarnya, ini sepatutnya mudah difahami secara dalaman rujukan secara semula jadi akan hilang!

Satu lagi situasi kebocoran memori: Apabila objek disimpan dalam koleksi HashSet, medan dalam objek yang mengambil bahagian dalam mengira nilai cincangan tidak boleh diubah suai daripada nilai cincang apabila ia pada asalnya disimpan dalam koleksi HashSet Dalam kes ini, walaupun kaedah mengandungi menggunakan rujukan semasa objek sebagai parameter untuk mendapatkan semula objek daripada koleksi HashSet, ia akan mengembalikan objek yang tidak ditemui. Akibatnya, ini juga akan mengakibatkan ketidakupayaan untuk memadamkan objek semasa secara individu daripada koleksi HashSet, menyebabkan kebocoran memori.

Lampiran: Situasi biasa kebocoran memori

(1) Masalah kebocoran memori jangka pendek yang disebabkan oleh struktur data, lihat kod berikut

public class Stack{  
      private Object[] element=new Object[10];  
      private int size=0;  
        
      public void push(Object ele){  
             ensureCapacity();  
             element[size++]=ele;  
      }  
  
      public Object pop(){  
             if(size==0) throw new EmptyStackException();  
             return element[--size]; //短暂造成内存泄露  
      }  
  
      private void ensureCapacity(){  
             if(element.length==size){  
                     Object[] oldElement=element;  
                     element=new Object[size*2+1];  
                     System.arraycopy(oldElement,0,element,0,size);  
             }  
      }  
}
Salin selepas log masuk

Kod di atas pop() setiap kali Stack akan muncul elemen setiap kali Sebelum menambah elemen baharu, sebenarnya masih terdapat elemen rujukan[x] yang menunjuk ke objek yang muncul, jadi GC tidak akan mengumpulnya. Hanya dengan menetapkan elemen[x]=newObject apabila menolak() elemen baharu boleh objek yang dicipta sebelum ini dikitar semula. Adalah lebih selamat untuk menukar kaedah pop() di atas kepada kod berikut:

public Object pop(){  
       if(element.length==size) throws EmptyStackException();  
       Object o=element[--size];  
       elements[size]=null;  //使得GC有机会回收这个对象  
       return o;  
}
Salin selepas log masuk

Atas ialah kandungan terperinci Analisis kes masalah kebocoran memori Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:yisu.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!