激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

香港云服务器
服務(wù)器之家 - 編程語言 - Java教程 - java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理分析

java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理分析

2022-02-15 16:00知我飯否 Java教程

這篇文章主要介紹了java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

java內(nèi)存管理關(guān)系及內(nèi)存泄露原理

這可能是最近寫的博客中最接近底層的了。閑言少敘,進(jìn)入正題。

java對象和內(nèi)存的關(guān)系

首先,我們要知道下面幾條真理(自己總結(jié)的)

  • 一個(gè)完整的建立對象流程是 1聲明對象,2開辟內(nèi)存空間,3將對象和內(nèi)存空間建立聯(lián)系。
  • 一個(gè)對象只能對應(yīng)一個(gè)內(nèi)存空間,一個(gè)內(nèi)存空間可以對應(yīng)很多對象
  • 回收一個(gè)內(nèi)存空間 。如果,這個(gè)內(nèi)存空間沒有任何一個(gè)對象和他有聯(lián)系。就可以被回收,或者好幾個(gè)對象環(huán)形引用,也會被回收
  • 對一個(gè)對象進(jìn)行操作的時(shí)候,是先通過 對象 找到 內(nèi)存空間,然后 對內(nèi)存空間進(jìn)行操作(讀,寫 改 刪)

這是本人總結(jié)出來的四條經(jīng)驗(yàn)。

特別重要的是,一定要有這種認(rèn)知。不管任何語言,最終都是要物理內(nèi)存上面反映的,對象 和 內(nèi)存空間 是兩個(gè)不同的個(gè)體。 如果 沒有的話,那么你會發(fā)現(xiàn) 下面將的都是什么啊!

創(chuàng)建對象

     Stu one; //只聲明 one對象 但是沒有分配內(nèi)存空間
      //用new 開辟新的內(nèi)存空間 oneMemory ,調(diào)用構(gòu)造函數(shù)賦值,并將內(nèi)存空間 oneMemory 與 one對象建立聯(lián)系。
      one = new Stu("one");
      
      //聲明 two對象 并開辟內(nèi)存 twoMemory 調(diào)用構(gòu)造函數(shù)賦值,并將內(nèi)存空間 twoMemory與 two對象建立聯(lián)系
      Stu two = new Stu("two");
      
      //聲明 three對象, 并找到one 對象聯(lián)系的內(nèi)存空間 oneMemory。并將 oneMemory與 three 對象建立聯(lián)系
      Stu three = one;
      
      //此時(shí) 內(nèi)存空間 oneMemory 與兩個(gè)對象有聯(lián)系。一個(gè)是 one對象,一個(gè)是three對象
      System.out.println("three 和 one 是否相等" + (three == one) + " one的哈希值" + one.hashCode() + " three的哈希值" + three.hashCode());

運(yùn)行結(jié)果

java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理分析

我們可以發(fā)現(xiàn),three對象 和one對象 指向的是同一個(gè)內(nèi)存空間oneMemory。這個(gè)不就是符合上面所說的第二個(gè)真理 如果,我們對one對象進(jìn)行操作,那么產(chǎn)生的影響,也會反映到three對象上。

因?yàn)椋?*他們指向的是同一個(gè)內(nèi)存空間,對one對象操作,就是做內(nèi)存空間oneMemory進(jìn)行操作。而three對象指向的也是oneMemory。這個(gè)符合上面第四條真理。**例子如下

      System.out.println("three 對象的值" + three.getName() + three.hashCode());
      //修改one的值,第一步 找到one對象聯(lián)系的內(nèi)存空間 oneMemory , 將內(nèi)存空間oneMemory 中的name值改變
      one.setName("change");
      //讀取three對象值時(shí)候,先找到three對象聯(lián)系的內(nèi)存空間oneMemory,讀取其中的name值
      System.out.println("three 對象的值" + three.getName() + three.hashCode());

null的作用

長久以來,我只知道,將一個(gè)值復(fù)制成null,那么他就是空的了。但是 完全不知道,為啥。

還是接著上面的例子,看一段代碼;

       //讀取three對象值時(shí)候,先找到three對象聯(lián)系的內(nèi)存空間oneMemory,讀取其中的name值
      System.out.println("three 對象的值 before" + three.getName() + three.hashCode());
      /*
       此時(shí) 如果 我們把one 對象 設(shè)置為null的。 對內(nèi)存空間 oneMemory 是沒有影響的
       =null的作用是 將one對象自己本身 對內(nèi)存空間的聯(lián)系去除,并不會影響到內(nèi)存空間和其他對象的聯(lián)系
       */
      one = null;
      System.out.println("three 對象的值  after" + three.getName() + three.hashCode());

運(yùn)行結(jié)果

java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理分析

我們會發(fā)現(xiàn) 將one對象賦值為空后,three對象還是和先前一樣。以前一直認(rèn)為null,是將對象和他的內(nèi)存空間清楚。但現(xiàn)在不是!。代碼注釋里面寫的很清楚了。null 并不是清除內(nèi)存空間,他只是把對象自己本身和內(nèi)存空間的聯(lián)系切斷了

內(nèi)存泄露

如果,你明白了上面。那么內(nèi)存泄露對你來說也很簡單了。

再來學(xué)習(xí)一個(gè)新概念

java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理分析

上面這么多呢。在本篇文章里面,你只需要記住 被static關(guān)鍵詞修飾的變量,類,方法的生命周期是伴隨整個(gè)程序的。就是程序活多久,他們就活多久

接下來看代碼

首先,我們定義一個(gè)靜態(tài)集合 staticList ,他是程序一運(yùn)行,就會被創(chuàng)建好的。程序結(jié)束運(yùn)行了,它才會被回收。

static List<Stu> staticList = new ArrayList<>();//開辟內(nèi)存空間 listMemory
     System.out.println("three 對象的值  after" + three.getName() + three.hashCode());
      /*
       內(nèi)存泄露 是長生命周期的對象 對一個(gè)內(nèi)存空間有聯(lián)系,造成內(nèi)存空間沒有辦法被回收
       */
      /*
      將three對象添加到靜態(tài)集合里面,步驟是這樣的,
      第一步 找到three對象聯(lián)系的內(nèi)存空間 oneMemory
      第二步 找到 staticList集合對象聯(lián)系的內(nèi)存空間 listMemory
      第三步 告訴系統(tǒng) staticList集合對象的部分成員 和內(nèi)存空間 oneMemory 建立聯(lián)系。
       */
      staticList.add(three);
      
      /*
      在這里 即使three對象已經(jīng)和內(nèi)存空間 oneMemory 沒有聯(lián)系了。
      oneMemory 也不會被回收,因?yàn)樯厦嬲f了內(nèi)存空間和對象的關(guān)系是1對多。
       而回收的條件是 一個(gè)內(nèi)存空間沒有一條和對象的聯(lián)系才可以回收。
       此時(shí) 內(nèi)存空間 和staticList集合對象的部分成員 有聯(lián)系,所以 內(nèi)存空間不會被回收。
       又由于staticList 集合對象聯(lián)系的內(nèi)存空間在 靜態(tài)存儲區(qū),是伴隨整個(gè)程序的。所以 在整個(gè)程序生命里面,
       內(nèi)存空間 oneMemory  就得不到 回收。  就是內(nèi)存泄露了。
       */
      three = null;
      System.out.println(staticList.get(0).hashCode());

運(yùn)行結(jié)果

java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理分析

可以看見。在我們將three對象賦值null切斷和內(nèi)存空間 oneMemory的聯(lián)系后。靜態(tài)集合staticList對象的部分成員依然和內(nèi)存空間 oneMemory有聯(lián)系。根據(jù)上面第三條所說,因?yàn)閮?nèi)存空間 oneMemory 還是和對象有聯(lián)系的(staticList)。所以不會回收oneMemory內(nèi)存空間。又由于staticList是靜態(tài)的,生命和程序一樣長。 那么在整個(gè)程序周期里面,oneMemory內(nèi)存空間 都不會被回收。就造成了內(nèi)存泄露。

附上完整的代碼

package com.zfh.test;
import java.util.ArrayList;
import java.util.List;
public class JavaMain {
  static List<Stu> staticList = new ArrayList<>();//開辟內(nèi)存空間 listMemory
  public static void main(String[] args) {
      Stu one; //只聲明 one對象 但是沒有分配內(nèi)存空間
      //用new 開辟新的內(nèi)存空間 oneMemory ,調(diào)用構(gòu)造函數(shù)賦值,并將內(nèi)存空間 oneMemory 與 one對象建立聯(lián)系。
      one = new Stu("one");
      //聲明 two對象 并開辟內(nèi)存 twoMemory 調(diào)用構(gòu)造函數(shù)賦值,并將內(nèi)存空間 twoMemory與 two對象建立聯(lián)系
      Stu two = new Stu("two");
      //聲明 three對象, 并找到one 對象聯(lián)系的內(nèi)存空間 oneMemory。并將 oneMemory與 three 對象建立聯(lián)系
      Stu three = one;
      //此時(shí) 內(nèi)存空間 oneMemory 與兩個(gè)對象有聯(lián)系。一個(gè)是 one對象,一個(gè)是three對象
      System.out.println("three 和 one 是否相等" + (three == one) + " one的哈希值" + one.hashCode() + " three的哈希值" + three.hashCode());
      System.out.println("three 對象的值" + three.getName() + three.hashCode());
      //修改one的值,第一步 找到one對象聯(lián)系的內(nèi)存空間 oneMemory , 將內(nèi)存空間oneMemory 中的name值改變
      one.setName("change");
      //讀取three對象值時(shí)候,先找到three對象聯(lián)系的內(nèi)存空間oneMemory,讀取其中的name值
      System.out.println("three 對象的值 before" + three.getName() + three.hashCode());
      /*
       此時(shí) 如果 我們把one 對象 設(shè)置為null的。 對內(nèi)存空間 oneMemory 是沒有影響的
       =null的作用是 將one對象自己本身 對內(nèi)存空間的聯(lián)系去除,并不會影響到內(nèi)存空間和其他對象的聯(lián)系
       */
      one = null;
      System.out.println("three 對象的值  after" + three.getName() + three.hashCode());
      /*
       內(nèi)存泄露 是長生命周期的對象 對一個(gè)內(nèi)存空間有聯(lián)系,造成內(nèi)存空間沒有辦法被回收
       */
      /*
      將three對象添加到靜態(tài)集合里面,步驟是這樣的,
      第一步 找到three對象聯(lián)系的內(nèi)存空間 oneMemory
      第二步 找到 staticList集合對象聯(lián)系的內(nèi)存空間 listMemory
      第三步 告訴系統(tǒng) staticList集合對象的部分成員 和內(nèi)存空間 oneMemory 建立聯(lián)系。
       */
      staticList.add(three);
      /*
      在這里 即使three對象已經(jīng)和內(nèi)存空間 oneMemory 沒有聯(lián)系了。
      oneMemory 也不會被回收,因?yàn)樯厦嬲f了內(nèi)存空間和對象的關(guān)系是1對多。
       而回收的條件是 一個(gè)內(nèi)存空間沒有一條和對象的聯(lián)系才可以回收。
       此時(shí) 內(nèi)存空間 和staticList集合對象的部分成員 有聯(lián)系,所以 內(nèi)存空間不會被回收。
       又由于staticList 集合對象聯(lián)系的內(nèi)存空間在 靜態(tài)存儲區(qū),是伴隨整個(gè)程序的。所以 在整個(gè)程序生命里面,
       內(nèi)存空間 oneMemory  就得不到 回收。  就是內(nèi)存泄露了。
       */
      three = null;
      System.out.println(staticList.get(0).hashCode());
  }
}

bean對象 即Stu

package com.zfh.test;
public class Stu {
/*  static {
      System.out.println("靜態(tài)代碼塊 我只調(diào)用一次");
  }*/

  private String name;
  
/*  {
      System.out.println("構(gòu)造代碼塊");
  }*/

  public Stu(String name) {
      this.name = name;
  }
  public String getName() {
      return name;
  }
  public void setName(String name) {
      this.name = name;
  }
  public void sout(){
      System.out.println(this.name+this.hashCode());
  }
  public void printer() {
      System.out.println(Stu.class.hashCode());
  }
  @Override
  protected void finalize() throws Throwable {
      super.finalize();
      System.out.println("終結(jié)了");
  }
}

 

檢測內(nèi)存泄露的原理

檢測內(nèi)存泄漏的關(guān)鍵是要能截獲住對分配內(nèi)存和釋放內(nèi)存的函數(shù)的調(diào)用。截獲住這兩個(gè)函數(shù),我們就能跟蹤每一塊內(nèi)存的生命周期,比如,每當(dāng)成功的分配一塊內(nèi)存后,就把它的指針加入一個(gè)全局的list中;每當(dāng)釋放一塊內(nèi)存,再把它的指針從list中刪除。這樣,當(dāng)程序結(jié)束的時(shí)候,list中剩余的指針就是指向那些沒有被釋放的內(nèi)存。這里只是簡單的描述了檢測內(nèi)存泄漏的基本原理,詳細(xì)的算法可以參見Steve Maguire的<<Writing Solid Code>>。  

如果要檢測堆內(nèi)存的泄漏,那么需要截獲住malloc/realloc/free和new/delete就可以了(其實(shí)new/delete最終也是用malloc/free的,所以只要截獲前面一組即可)。對于其他的泄漏,可以采用類似的方法,截獲住相應(yīng)的分配和釋放函數(shù)。比如,要檢測BSTR的泄漏,就需要截獲SysAllocString/SysFreeString;要檢測HMENU的泄漏,就需要截獲CreateMenu/ DestroyMenu。(有的資源的分配函數(shù)有多個(gè),釋放函數(shù)只有一個(gè),比如,SysAllocStringLen也可以用來分配BSTR,這時(shí)就需要截獲多個(gè)分配函數(shù))。

在Windows平臺下,檢測內(nèi)存泄漏的工具常用的一般有三種,MS C-Runtime Library內(nèi)建的檢測功能;外掛式的檢測工具,諸如,Purify,BoundsChecker等;利用Windows NT自帶的Performance Monitor。這三種工具各有優(yōu)缺點(diǎn),MS C-Runtime Library雖然功能上較之外掛式的工具要弱,但是它是免費(fèi)的;Performance Monitor雖然無法標(biāo)示出發(fā)生問題的代碼,但是它能檢測出隱式的內(nèi)存泄漏的存在,這是其他兩類工具無能為力的地方。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://blog.csdn.net/a1064072510/article/details/83148538

延伸 · 閱讀

精彩推薦
1124
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 人人做人人看 | 日韩精品久久久久久久电影99爱 | 99国产精品欲a | 欧美成人精品h版在线观看 久久久久久三区 | 亚洲欧美日韩在线 | 今井夏帆av一区二区 | 久久亚洲春色中文字幕久久 | 欧美成人午夜精品久久久 | 亚洲五码在线观看视频 | 一级黄色电影网站 | 农村寡妇偷毛片一级 | 成人国产精品一区二区毛片在线 | 久久精品国产一区二区 | 91成人久久 | 黄色一级片免费观看 | 久久99精品久久久久久秒播放器 | 激情综合视频 | 干少妇av| 看一级毛片 | 一区二区视 | hdbbwsexvideo | 亚久久| 在线看91 | 免费a级毛片永久免费 | 日日鲁一鲁视频 | 国产在线观看av | 精品一区二区久久久久久久网精 | 思思久而久而蕉人 | av电影直播 | av不卡免费在线 | 黄色av网站在线观看 | 色骚综合| 综合网天天色 | 中文字幕涩涩久久乱小说 | 日本一区二区免费在线观看 | fc2国产成人免费视频 | 国产成人在线一区二区 | 黄色片网站免费观看 | 人禽l交免费视频观看 视频 | 直接在线观看的三级网址 | 欧美一级黄 |