首頁>技術>

然而,隨著時間的推移,{大多數|相當多|一些}真實世界的Java程式隨著時間的推移成為可怕的記憶體吞噬者的現實

Java中存在記憶體洩漏

我會根據你所在的營地選擇一個,但不要忘記Eclipse和OpenHAB

句法和語義記憶體洩露

任何一個不太好的垃圾回收器都會確保不可訪問的物件被清除;但是,儘管所有不可訪問的物件都是無用的,

並非所有無用的物件都是不可訪問的

將那些無法訪問但仍存在於程式中的物件稱為語法記憶體洩漏,以及那些無用但仍然可以訪問的物件稱為語義記憶體洩漏。

事實上,它是“終將被清理乾淨”,但本著對那些已經受苦受難的人友善的精神,我們將暫時忘記這個詞

Java記憶體中的語義洩漏

Java中出現記憶體洩漏的常見情況有很多,但大多數情況歸結為要麼忘記從某個集合中刪除對某個項的引用,要麼忘記設定不再需要的對null的引用。實際上,如果我們在一個集合中保留一些無用的東西,或者保留對一個不再需要的物件的引用而沒有機會再次使用這個引用,那麼我們確實存在語義記憶體洩漏。

有些作者傾向於將後一個問題簡單化為“嘿,讓我們小心可變靜態資料”;然而,由於對可變靜態/全域性資料(是的,這包括單例資料)的不尊重,我不得不說語義記憶體洩漏的問題並不侷限於靜態(事實上,靜態只是一種特殊的資料)現有但從未使用過的案例)。例如,即使我把非空引用放在堆疊上,它也不會被釋放,直到我超過堆疊中的這一點——這取決於應用程式,它可以很容易地持續到app will uspart的死亡。

一個這樣的例子是一個物件,它的引用由main()函式儲存。更一般地說,只要我們有任何型別的頂級迴圈(比如事件迴圈),那麼事件迴圈為我們保留的所有物件,包括透過來自任何此類物件的引用可訪問的所有物件,都需要手動將其引用設為空,以避免此類引用成為語義記憶體洩漏。

讓我們比較以下三段程式碼:

//pre-C++11 C++struct State {  uint8_t* data;   void addData() {    data = new uint8_t[1000000];    //do something with data  }  void removeData() {    delete [] data;    data = nullptr;//(*)  }  ~State() {    delete [] data;  }};//post-C++11 C++struct State {  std::unique_ptr<uint8_t[]> data;   void addData() {    data = make_unique<uint8_t[]>(1'000'000);    //do something with data  }  void removeData() {    data.reset();//(*)  }};//JAVAclass State {  byte[] data;   void addData() {    data = new byte[1000000];    //do something with data  }  void removeData() {    data = null;//(*)   } };

從我目前的觀點來看,這三段程式碼在語義上是完全相同的(即,唯一的區別是關於語法的——TBH也沒有太大區別)。

他們真的一模一樣嗎?嗯,不完全是…

儘管在這方面兩種程式語言下可以被視為“安全和無記憶體洩漏的程式碼”之間有著驚人的相似之處,但仍然有一個主要的區別。

具體來說,如果我們忘記將null賦給以(*)(或呼叫CeSeCe(11)C++)標記的行中的資料,則效果將不同:

C++懲罰訪問已刪除的資料,最壞的情況是資料被破壞Java在這方面明顯更為寬鬆,而遺忘的data=null只會受到語義記憶體洩漏的懲罰。正是這種寬容導致了Java程式中語義記憶體洩漏無處不在:一個C++程式崩潰是一個明顯的錯誤,它比java程式更容易被固定,語義記憶體洩漏(除java以外),記憶體洩漏常常不明顯,直到有人執行程式很多小時。在大多數常規測試中被忽略此外,在Java中,即使在我們這裡為null之後,也有機會讓其他類的例項引用資料。據我所見,這種隱藏的引用是複雜的真實Java程式中語義記憶體洩漏的主要來源。C++ C++ 11的行為在這方面更像java。它仍然與java完全不同,因為C++的unique_ptr<>保證是對資料物件的唯一引用。這反過來又消除了那些類似Java的隱藏引用,從而大大減少了我們發生語義記憶體洩漏的可能性。然而,C++下,這樣一個隱藏的引用將變成一個懸空指標,再次引起記憶體損壞。總結

在C++和java環境下,程式碼可以被認為是“好”記憶體(從崩潰和記憶體洩漏中安全)。

是的,與很多書中所告訴我們的相反,即使在用Java程式設計時,我們也必須考慮記憶體管理(嘿,有人會說data=null是手動記憶體管理)。

然而,如果我們偏離了這種“好”程式碼實踐,不同的程式語言將懲罰我們不同的(C++中的可能是崩潰或記憶體損壞,在java中它可能是語義記憶體洩漏)。

換句話說,當從C++移動到java時,我們正在進行記憶體洩漏的崩潰處理。

由於記憶體洩漏不像崩潰那樣明顯,它們有生存更長時間(通常更長)的趨勢。換句話說,當從C++移動到java時,我們傾向於處理一些崩潰來儲存大量的記憶體洩漏,BTW傾向於與我個人的任何經驗/軼事證據一致。我不想爭論這是否是一個很好的權衡。

原文連結:http://javakk.com/1115.html

14
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 微軟開源 Python 自動化神器 Playwright