深入理解Java垃圾回收機制以及記憶體洩漏
前言
在segmentfault上看到一個問題:java有完善的GC機制,那麼在java中是否會出現記憶體洩漏的問題,以及能否給出一個記憶體洩漏的案例。本問題視圖給出此問題的完整答案。
垃圾回收機制簡介
在程式運作過程中,每建立一個物件都會被分配一定的記憶體以儲存物件資料。如果只是不停的分配內存,那麼程式遲早會面臨內存不足的問題。所以在任何語言中,都會有一個記憶體回收機制來釋放過期物件的內存,以確保記憶體能夠重複使用。
記憶體回收機制依照實現角色的不同可以分為兩種,一種是程式設計師手動實現記憶體的釋放(例如C語言)另一種則是語言內建的記憶體回收機制例如本文將要介紹的java垃圾回收機制。
Java的垃圾回收機制
在程式的運行時環境中,java虛擬機提供了一個系統級的垃圾回收(GC,Carbage Collection)線程,它負責回收失去引用的物件佔用的記憶體。理解GC的前提是理解一些和垃圾回收相關的概念,下文一一介紹這些概念。
物件在jvm堆區的狀態
Java物件的實例儲存在jvm的堆疊區,對於GC執行緒來說,這些物件有三種狀態。
1. 可觸及狀態:程式中還有變數引用,那麼此物件為可觸及狀態。
2. 可復活狀態:當程式中已經沒有變數引用這個對象,那麼此對象由可觸及狀態轉為可復活狀態。 CG執行緒將在一定的時間準備呼叫此物件的finalize方法(finalize方法繼承或重寫子Object),finalize方法內的程式碼有可能將物件轉為可觸及狀態,否則物件轉換為不可觸及狀態。
3. 不可觸及狀態:只有當物件處於不可觸及狀態時,GC執行緒才能回收此物件的記憶體。
GC為了能夠正確釋放對象,必須監控每個對象的運作狀態,包括對象的申請、引用、被引用、賦值等,GC都需要監控,所以無論一個對象處於上文的任何狀態GC都會知道。
上文說到,GC執行緒會在一定的時間執行可復活狀態物件的finalize方法,那麼何時執行呢?由於不同的JVM實作者可能會使用不同的演算法來管理GC,所以在任何時候,開發者無法預料GC執行緒進行各項操作(包括偵測物件狀態、釋放物件記憶體、呼叫物件的finalize方法)的時機。雖然可以透過System.gc()和Runtime.gc()函數提醒GC執行緒盡快進行垃圾回收操作,但這也無法保證GC執行緒馬上就會進行對應的回收操作。
記憶體洩漏
記憶體洩漏指由於錯誤的設計造成程式未能釋放已經不再使用的內存,造成資源浪費。 GC會自動清理失去引用的物件所佔用的記憶體。但是,由於程式設計錯誤而導致某些物件始終被引用,那麼將會出現記憶體洩漏。
例如下面的例子。使用陣列實作了一個棧,有入棧和出棧兩個操作。
import com.sun.javafx.collections.ElementObservableListDecorator; import com.sun.swing.internal.plaf.metal.resources.metal_sv; import java.beans.ExceptionListener; import java.util.EmptyStackException; /** * Created by peng on 14-9-21. */ public class MyStack { private Object[] elements; private int Increment = 10; private int size = 0; public MyStack(int size) { elements = new Object[size]; } //入栈 public void push(Object o) { capacity(); elements[size++] = o; } //出栈 public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } //增加栈的容量 private void capacity() { if (elements.length != size) return; Object[] newArray = new Object[elements.length + Increment]; System.arraycopy(elements, 0, newArray, 0, size); } public static void main(String[] args) { MyStack stack = new MyStack(100); for (int i = 0; i < 100; i++) stack.push(new Integer(i)); for (int i = 0; i < 100; i++) { System.out.println(stack.pop().toString()); } } }
這個程式是可用的,支援常用的入棧和出棧操作。但是,有一個問題沒有處理好,就是當出棧操作的時候,並沒有釋放數組中出棧元素的引用,這導致程式將一直保持對這個Object的引用(此object由數組引用),GC永遠認為此物件是可觸及的,也就更加談不上釋放其記憶體了。這就是記憶體洩漏的一個典型案例。針對此,修改後的程式碼為:
//出栈 public Object pop() { if (size == 0) throw new EmptyStackException(); Object o = elements[--size]; elements[size] = null; return o; }
以上這篇深入理解Java垃圾回收機制以及內存洩漏就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持PHP中文網。
更多深入理解Java垃圾回收機制以及內存洩漏相關文章請關注PHP中文網!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

公司安全軟件導致部分應用無法正常運行的排查與解決方法許多公司為了保障內部網絡安全,會部署安全軟件。 ...

將姓名轉換為數字以實現排序的解決方案在許多應用場景中,用戶可能需要在群組中進行排序,尤其是在一個用...

系統對接中的字段映射處理在進行系統對接時,常常會遇到一個棘手的問題:如何將A系統的接口字段有效地映�...

在使用IntelliJIDEAUltimate版本啟動Spring...

在使用MyBatis-Plus或其他ORM框架進行數據庫操作時,經常需要根據實體類的屬性名構造查詢條件。如果每次都手動...

Java對象與數組的轉換:深入探討強制類型轉換的風險與正確方法很多Java初學者會遇到將一個對象轉換成數組的�...

電商平台SKU和SPU表設計詳解本文將探討電商平台中SKU和SPU的數據庫設計問題,特別是如何處理用戶自定義銷售屬...

Redis緩存方案如何實現產品排行榜列表的需求?在開發過程中,我們常常需要處理排行榜的需求,例如展示一個�...
