1、既然有GC機(jī)制,為什么還會有內(nèi)存泄露的情況?
理論上Java因?yàn)橛欣厥諜C(jī)制(GC)不會存在內(nèi)存泄露問題(這也是Java被廣泛使用于服務(wù)器端編程的一個重要原因)。然而在實(shí)際開發(fā)中,可能會存在無用但可達(dá)的對象,這些對象不能被GC回收,因此也會導(dǎo)致內(nèi)存泄露的發(fā)生。
例如hibernate的Session(一級緩存)中的對象屬于持久態(tài),垃圾回收器是不會回收這些對象的,然而這些對象中可能存在無用的垃圾對象,如果不及時關(guān)閉(close)或清空(flush)一級緩存就可能導(dǎo)致內(nèi)存泄露。
下面例子中的代碼也會導(dǎo)致內(nèi)存泄露。
import java.util.Arrays; import java.util.EmptyStackException; public class MyStack<T> { private T[] elements; private int size = 0; private static final int INIT_CAPACITY = 16; public MyStack() { elements = (T[]) new Object[INIT_CAPACITY]; } public void push(T elem) { ensureCapacity(); elements[size++] = elem; } public T pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if (elements.length == size) { elements = Arrays.copyOf(elements,2 * size + 1); } } }
上面的代碼實(shí)現(xiàn)了一個棧(先進(jìn)后出(FILO))結(jié)構(gòu),乍看之下似乎沒有什么明顯的問題,它甚至可以通過你編寫的各種單元測試。
然而其中的pop方法卻存在內(nèi)存泄露的問題,當(dāng)我們用pop方法彈出棧中的對象時,該對象不會被當(dāng)作垃圾回收,即使使用棧的程序不再引用這些對象,因?yàn)闂?nèi)部維護(hù)著對這些對象的過期引用(obsolete reference)。在支持垃圾回收的語言中,內(nèi)存泄露是很隱蔽的,這種內(nèi)存泄露其實(shí)就是無意識的對象保持。
如果一個對象引用被無意識的保留起來了,那么垃圾回收器不會處理這個對象,也不會處理該對象引用的其他對象,即使這樣的對象只有少數(shù)幾個,也可能會導(dǎo)致很多的對象被排除在垃圾回收之外,從而對性能造成重大影響,極端情況下會引發(fā)Disk Paging(物理內(nèi)存與硬盤的虛擬內(nèi)存交換數(shù)據(jù)),甚至造成OutOfMemoryError。
2、Java中為什么會有GC機(jī)制呢?
·安全性考慮;--for security.
·減少內(nèi)存泄露;--erase memory leak in some degree.
·減少程序員工作量。--Programmers dont worry about memory releasing.
3、對于Java的GC哪些內(nèi)存需要回收?
內(nèi)存運(yùn)行時JVM會有一個運(yùn)行時數(shù)據(jù)區(qū)來管理內(nèi)存。
它主要包括5大部分:
程序計(jì)數(shù)器(Program CounterRegister);
虛擬機(jī)棧(VM Stack);
本地方法棧(Native Method Stack);
方法區(qū)(Method Area);
堆(Heap)。
而其中程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧是每個線程私有的內(nèi)存空間,隨線程而生,隨線程而亡。例如棧中每一個棧幀中分配多少內(nèi)存基本上在類結(jié)構(gòu)確定是哪個時就已知了,因此這3個區(qū)域的內(nèi)存分配和回收都是確定的,無需考慮內(nèi)存回收的問題。
但方法區(qū)和堆就不同了,一個接口的多個實(shí)現(xiàn)類需要的內(nèi)存可能不一樣,我們只有在程序運(yùn)行期間才會知道會創(chuàng)建哪些對象,這部分內(nèi)存的分配和回收都是動態(tài)的,GC主要關(guān)注的是這部分內(nèi)存??偠灾珿C主要進(jìn)行回收的內(nèi)存是JVM中的方法區(qū)和堆。
4、Java的GC什么時候回收垃圾?
在面試中經(jīng)常會碰到這樣一個問題(事實(shí)上筆者也碰到過):如何判斷一個對象已經(jīng)死去?
很容易想到的一個答案是:對一個對象添加引用計(jì)數(shù)器。每當(dāng)有地方引用它時,計(jì)數(shù)器值加1;當(dāng)引用失效時,計(jì)數(shù)器值減1.而當(dāng)計(jì)數(shù)器的值為0時這個對象就不會再被使用,判斷為已死。是不是簡單又直觀。
然而,很遺憾。這種做法是錯誤的!為什么是錯的呢?事實(shí)上,用引用計(jì)數(shù)法確實(shí)在大部分情況下是一個不錯的解決方案,而在實(shí)際的應(yīng)用中也有不少案例,但它卻無法解決對象之間的循環(huán)引用問題。
比如對象A中有一個字段指向了對象B,而對象B中也有一個字段指向了對象A,而事實(shí)上他們倆都不再使用,但計(jì)數(shù)器的值永遠(yuǎn)都不可能為0,也就不會被回收,然后就發(fā)生了內(nèi)存泄露。
正確的做法應(yīng)該是怎樣呢?
在Java,C#等語言中,比較主流的判定一個對象已死的方法是:可達(dá)性分析(Reachability Analysis).所有生成的對象都是一個稱為"GC Roots"的根的子樹。
從GC Roots開始向下搜索,搜索所經(jīng)過的路徑稱為引用鏈(Reference Chain),當(dāng)一個對象到GC Roots沒有任何引用鏈可以到達(dá)時,就稱這個對象是不可達(dá)的(不可引用的),也就是可以被GC回收了。
無論是引用計(jì)數(shù)器還是可達(dá)性分析,判定對象是否存活都與引用有關(guān)!那么,如何定義對象的引用呢?
我們希望給出這樣一類描述:當(dāng)內(nèi)存空間還夠時,能夠保存在內(nèi)存中;如果進(jìn)行了垃圾回收之后內(nèi)存空間仍舊非常緊張,則可以拋棄這些對象。所以根據(jù)不同的需求,給出如下四種引用,根據(jù)引用類型的不同,GC回收時也會有不同的操作:
強(qiáng)引用(Strong Reference):Object obj=new Object();只要強(qiáng)引用還存在,GC永遠(yuǎn)不會回收掉被引用的對象。
軟引用(Soft Reference):描述一些還有用但非必需的對象。在系統(tǒng)將會發(fā)生內(nèi)存溢出之前,會把這些對象列入回收范圍進(jìn)行二次回收(即系統(tǒng)將會發(fā)生內(nèi)存溢出了,才會對他們進(jìn)行回收)
弱引用(Weak Reference):程度比軟引用還要弱一些。這些對象只能生存到下次GC之前。當(dāng)GC工作時,無論內(nèi)存是否足夠都會將其回收(即只要進(jìn)行GC,就會對他們進(jìn)行回收。)
虛引用(Phantom Reference):一個對象是否存在虛引用,完全不會對其生存時間構(gòu)成影響。關(guān)于方法區(qū)中需要回收的是一些廢棄的常量和無用的類。
1.廢棄的常量的回收。這里看引用計(jì)數(shù)就可以了。沒有對象引用該常量就可以放心的回收了。
2.無用的類的回收。什么是無用的類呢?
A.該類所有的實(shí)例都已經(jīng)被回收。也就是Java堆中不存在該類的任何實(shí)例;
B加載該類的ClassLoader已經(jīng)被回收;
C.該類對應(yīng)的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。
總而言之:對于堆中的對象,主要用可達(dá)性分析判斷一個對象是否還存在引用,如果該對象沒有任何引用就應(yīng)該被回收。而根據(jù)我們實(shí)際對引用的不同需求,又分成了4種引用,每種引用的回收機(jī)制也是不同的。
對于方法區(qū)中的常量和類,當(dāng)一個常量沒有任何對象引用它,它就可以被回收了。而對于類,如果可以判定它為無用類,就可以被回收了。
5、通過10個示例來初步認(rèn)識Java8中的lambda表達(dá)式
用lambda表達(dá)式實(shí)現(xiàn)Runnable
// Java 8 之前: new Thread(new Runnable(){ @Override public void run(){ System.out.println("Before Java8, too much code for too little to do"); }}).start(); //Java 8 方式: new Thread(()->System.out.println("In Java8, Lambda expression rocks !!")).start();
輸出:
too much code,for too little to do Lambda expression rocks!!
這個例子向我們展示了Java 8 lambda表達(dá)式的語法。你可以使用lambda寫出如下代碼:
(params) -> expression (params) -> statement (params) -> { statements }
例如,如果你的方法不對參數(shù)進(jìn)行修改、重寫,只是在控制臺打印點(diǎn)東西的話,那么可以這樣寫:
() -> System.out.println("Hello Lambda Expressions");
如果你的方法接收兩個參數(shù),那么可以寫成如下這樣:
(int even, int odd) -> even + odd
順便提一句,通常都會把lambda表達(dá)式內(nèi)部變量的名字起得短一些。這樣能使代碼更簡短,放在同一行。所以,在上述代碼中,變量名選用a、b或者x、y會比even、odd要好。
使用Java 8 lambda表達(dá)式進(jìn)行事件處理
如果你用過Swing API編程,你就會記得怎樣寫事件監(jiān)聽代碼。這又是一個舊版本簡單匿名類的經(jīng)典用例,但現(xiàn)在可以不這樣了。你可以用lambda表達(dá)式寫出更好的事件監(jiān)聽代碼,如下所示:
// Java 8 之前: JButton show = new JButton("Show"); show.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Event handling without lambda expression is boring"); } }); // Java 8 方式: show.addActionListener((e) -> { System.out.println("Light, Camera, Action !! Lambda expressions Rocks"); });
使用Java 8 lambda表達(dá)式進(jìn)行事件處理 使用lambda表達(dá)式對列表進(jìn)行迭代
如果你使過幾年Java,你就知道針對集合類,最常見的操作就是進(jìn)行迭代,并將業(yè)務(wù)邏輯應(yīng)用于各個元素,例如處理訂單、交易和事件的列表。
由于Java是命令式語言,Java 8之前的所有循環(huán)代碼都是順序的,即可以對其元素進(jìn)行并行化處理。如果你想做并行過濾,就需要自己寫代碼,這并不是那么容易。
通過引入lambda表達(dá)式和默認(rèn)方法,將做什么和怎么做的問題分開了,這意味著Java集合現(xiàn)在知道怎樣做迭代,并可以在API層面對集合元素進(jìn)行并行處理。
下面的例子里,我將介紹如何在使用lambda或不使用lambda表達(dá)式的情況下迭代列表。你可以看到列表現(xiàn)在有了一個forEach()方法,它可以迭代所有對象,并將你的lambda代碼應(yīng)用在其中。
// Java 8 之前: List features = Arrays.asList("Lambdas", "Default Method", "Stream API","Date and Time API"); for (String feature : features) { System.out.println(feature); } // Java 8 之后: List features = Arrays.asList("Lambdas", "Default Method", "Stream API","Date and Time API"); features.forEach(n -> System.out.println(n)); // 使用 Java 8 的方法引用更方便,方法引用由::雙冒號操作符標(biāo)示, // 看起來像 C++的作用域解析運(yùn)算符 features.forEach(System.out::println);
輸出:
Lambdas Default Method Stream API Date and Time API
列表循環(huán)的最后一個例子展示了如何在Java 8中使用方法引用(method reference)。你可以看到C++里面的雙冒號、范圍解析操作符現(xiàn)在在Java 8中用來表示方法引用。
使用lambda表達(dá)式和函數(shù)式接口Predicate
除了在語言層面支持函數(shù)式編程風(fēng)格,Java 8也添加了一個包,叫做java.util.function。它包含了很多類,用來支持Java的函數(shù)式編程。其中一個便是Predicate,使用java.util.function.Predicate函數(shù)式接口以及l(fā)ambda表達(dá)式,可以向API方法添加邏輯,用更少的代碼支持更多的動態(tài)行為。下面是Java 8 Predicate的例子,展示了過濾集合數(shù)據(jù)的多種常用方法。Predicate接口非常適用于做過濾。
public static void main(String[]args){ List languages=Arrays.asList("Java", "Scala","C++", "Haskell", "Lisp"); System.out.println("Languages which starts with J :"); filter(languages, (str)->str.startsWith("J")); System.out.println("Languages which ends with a "); filter(languages, (str)->str.endsWith("a")); System.out.println("Print all languages :"); filter(languages, (str)->true); System.out.println("Print no language : "); filter(languages, (str)->false); System.out.println("Print language whose length greater than 4:"); filter(languages, (str)->str.length()>4); } public static void filter(List names, Predicate condition){ for(String name:names){ if(condition.test(name)){ System.out.println(name+" "); } } } // filter 更好的辦法--filter 方法改進(jìn) public static void filter(List names, Predicate condition) { names.stream().filter((name)->(condition.test(name))).forEach((name)-> {System.out.println(name + " "); }); }
可以看到,Stream API的過濾方法也接受一個Predicate,這意味著可以將我們定制的filter()方法替換成寫在里面的內(nèi)聯(lián)代碼,這就是lambda表達(dá)式的魔力。另外,Predicate接口也允許進(jìn)行多重條件的測試。
Atas ialah kandungan terperinci java gc 面試題及答案(1~5題). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Untuk mengendalikan transaksi JDBC dengan betul, anda mesti terlebih dahulu mematikan mod komit automatik, kemudian melakukan pelbagai operasi, dan akhirnya melakukan atau mengembalikan semula hasilnya; 1. Panggil Conn.SetAutOcommit (palsu) untuk memulakan transaksi; 2. Melaksanakan pelbagai operasi SQL, seperti memasukkan dan mengemaskini; 3. Panggil Conn.Commit () jika semua operasi berjaya, dan hubungi conn.rollback () jika pengecualian berlaku untuk memastikan konsistensi data; Pada masa yang sama, cuba-dengan-sumber harus digunakan untuk menguruskan sumber, mengendalikan pengecualian dengan betul dan menutup sambungan untuk mengelakkan kebocoran sambungan; Di samping itu, adalah disyorkan untuk menggunakan kolam sambungan dan menetapkan mata simpan untuk mencapai rollback separa, dan menyimpan urus niaga sesingkat mungkin untuk meningkatkan prestasi.

Gunakan kelas dalam pakej Java.Time untuk menggantikan kelas lama dan kelas kalendar; 2. Dapatkan tarikh dan masa semasa melalui LocalDate, LocalDateTime dan Tempatan Tempatan; 3. Buat tarikh dan masa tertentu menggunakan kaedah (); 4. Gunakan kaedah tambah/tolak untuk meningkatkan dan mengurangkan masa; 5. Gunakan zoneddatetime dan zonid untuk memproses zon waktu; 6. Format dan parse date string melalui DateTimeFormatter; 7. Gunakan segera untuk bersesuaian dengan jenis tarikh lama apabila perlu; pemprosesan tarikh di java moden harus memberi keutamaan untuk menggunakan java.timeapi, yang memberikan jelas, tidak berubah dan linear

Pra-formancetartuptimemoryusage, quarkusandmicronautleadduetocompile-timeprocessingandgraalvsupport, withquarkusoftenperforminglightbetterine serverless scenarios.tyvelopecosyste,

NetworkPortsandFireWallSworkTogethertoenableCommunicationWileensuringsecurity.1.networkportsarevirtualendpointsNumbered0-655 35, Withwell-KnownportsLike80 (http), 443 (https), 22 (ssh), dan25 (smtp) identitispecificservices.2.portsoperateovertcp (boleh dipercayai, c

Koleksi Sampah Java (GC) adalah mekanisme yang secara automatik menguruskan ingatan, yang mengurangkan risiko kebocoran ingatan dengan menuntut semula objek yang tidak dapat dicapai. 1.GC menghakimi kebolehcapaian objek dari objek akar (seperti pembolehubah stack, benang aktif, medan statik, dan lain -lain), dan objek yang tidak dapat dicapai ditandakan sebagai sampah. 2. Berdasarkan algoritma penandaan tanda, tandakan semua objek yang dapat dicapai dan objek yang tidak ditandai. 3. Mengamalkan strategi pengumpulan generasi: Generasi Baru (Eden, S0, S1) sering melaksanakan MinorGC; Orang tua melakukan kurang tetapi mengambil masa lebih lama untuk melakukan MajorGC; Metaspace Stores Metadata kelas. 4. JVM menyediakan pelbagai peranti GC: SerialGC sesuai untuk aplikasi kecil; ParallelGC meningkatkan throughput; CMS mengurangkan

Memilih jenis htmlinput yang betul dapat meningkatkan ketepatan data, meningkatkan pengalaman pengguna, dan meningkatkan kebolehgunaan. 1. Pilih jenis input yang sepadan mengikut jenis data, seperti teks, e -mel, tel, nombor dan tarikh, yang secara automatik boleh menyemak dan menyesuaikan diri dengan papan kekunci; 2. Gunakan HTML5 untuk menambah jenis baru seperti URL, Warna, Julat dan Carian, yang dapat memberikan kaedah interaksi yang lebih intuitif; 3. Gunakan pemegang tempat dan sifat -sifat yang diperlukan untuk meningkatkan kecekapan dan ketepatan pengisian bentuk, tetapi harus diperhatikan bahawa pemegang tempat tidak dapat menggantikan label.

GradleisthebetterChoiceFormostNewProjectSduetoitSsuperiorflexibility, Prestasi, danModernToolingSupport.1.Gradle'sGroovy/KOT lindslismoreconciseandexpressivethanmaven'sverbosexml.2.GradleOutPerformsMaveninBuildSpeedWithIncrementalcompilation, BuildCac

Defer digunakan untuk melaksanakan operasi tertentu sebelum fungsi pulangan, seperti sumber pembersihan; Parameter dinilai dengan serta-merta apabila menangguhkan, dan fungsi-fungsi dilaksanakan mengikut urutan terakhir (LIFO); 1. Pelbagai penahanan dilaksanakan dalam urutan terbalik pengisytiharan; 2. Biasanya digunakan untuk pembersihan yang selamat seperti penutupan fail; 3. Nilai pulangan yang dinamakan boleh diubah suai; 4. Ia akan dilaksanakan walaupun panik berlaku, sesuai untuk pemulihan; 5. Elakkan penyalahgunaan menangguhkan gelung untuk mengelakkan kebocoran sumber; Penggunaan yang betul boleh meningkatkan keselamatan kod dan kebolehbacaan.
