JavaScript對記憶體的使用

weixin_34302561發表於2018-06-05

記憶體的分配(示意)

啟動程式,就需要分配記憶體給執行的程式。啟動瀏覽器,就會分配一定記憶體供瀏覽器使用,瀏覽器在會分配相應的記憶體供諸如HTML+CSS,JS,'HTTP','其他外掛、定時器`等模組使用,如下圖。
記憶體的分配

會有一部分記憶體供JS模組使用,JS一般會將JS程式碼儲存在程式碼區,資料區內,通過某種聯絡將程式碼和資料對應在一起,如下圖。
記憶體的儲存

記憶體圖

示意圖

記憶體圖就是簡化模擬示意JS使用的記憶體中的資料區中的情況,簡單的分為棧記憶體Stack,堆記憶體Heap,如下圖。明顯,左邊是原始程式碼,中間是棧記憶體,右邊是堆記憶體
記憶體圖

使用

左邊原始程式碼定義一個變數,在棧記憶體中就會用64位儲存一個值。如果原始程式碼中變數是非物件棧記憶體中這個值就是直接值堆記憶體沒有資料。如果原始程式碼中變數是物件棧記憶體中就會儲存堆記憶體的地址(隨機),堆記憶體中會儲存這個物件的所有內容
記憶體圖使用_1_1

看到上個圖,原始程式碼區裡最後一行O2=O,將一個物件賦值給另一個變數時,實際上是將堆記憶體的地址賦值給另一個變數,轉換如下圖,O2在棧記憶體中的內容就變成了和O一樣的堆記憶體地址
記憶體圖使用_1_2

應用例項

第一個

  • 原始程式碼中定義變數a=1,Stack中儲存1
  • 原始程式碼中定義變數b=a,Stack中儲存b的值和a一樣,為1
  • 原始程式碼中賦值b=2,都是非物件,Stack中直接將b的值改為2,不影響a
  • 全程非物件,所以沒有涉及堆記憶體Heap

資料型別面試題_1

第二個

  • 原始程式碼中定義變數a={name:'a'},是個物件,隨機分配Heap地址(比如:31)並在Heap中儲存這個物件,在Stack中儲存這個Heap地址,比如ADDR 31
  • 原始程式碼中定義變數b=a,是個存在的物件,將a的Stack值(ADDR 31)(Heap地址)賦給b的Stack值
  • 原始程式碼中賦值b=null,賦給了b一個非物件,將b的Stack值改為null,不影響a
  • 全程操作Stack值,物件的Stack值為Heap地址

資料型別面試題_2

第三個

  • 原始程式碼定義變數a={n:1},隨機分配Heap地址(比如:34)並在Heap中儲存這個物件,在Stack中儲存這個Heap地址,比如ADDR 34
  • 原始程式碼中定義變數b=a,是個存在的物件,將a的Stack值(ADDR 34)(Heap地址)賦給b的Stack值
  • a.x=a={n:2},這句話閱讀順序從左往右。首先,在Heap 34中新增新屬性x:a,現在a的值是ADDR 34,所以新屬性相當於x:ADDR 34。然後,把{n:2}賦值給a,因為是個新物件,所以重新分配Heap地址(ADDR 54),並把a的Stack值變更為新的Heap地址(ADDR 51)。
  • alert(a.x),現在a的值實際是ADDR 54ADDR 54裡面是沒有x這個屬性的,所以返回undefined
  • alert(b.x),b一直是ADDR 34,其中x屬性值為ADDR 54,所以是個物件,返回[object Object]
  • 總之就是,原始程式碼裡對物件的操作都在堆記憶體Heap中實現,對變數的操作都在棧記憶體Stack中實現。非物件的Stack值就是直接值,物件的Stack值是堆記憶體Heap的地址

資料型別面試題_3

第四個

  • 原始程式碼中定義變數a={name:'a'},Heap中儲存物件,Stack中儲存Heap地址(ADDR 101)
  • 原始程式碼b=a,把a的Stack值(Heap地址)賦給b的Stack值
  • 原始程式碼b={'name':'b'},賦給b一個新物件,Heap中儲存新物件,b的Stack值變更為新的Heap地址(ADDR 301)
  • 所以,a.name沒有變,還是a

資料型別面試題_4

第五個

  • 原始程式碼中定義變數a={name:'a'},Heap中儲存物件,Stack中儲存Heap地址(ADDR 51)
  • 原始程式碼b=a,把a的Stack值(Heap地址)賦給b的Stack值
  • 原始程式碼設定b.name=b,就是ADDR 51中的name值變更為b
  • 所以,a.name也就是ADDR 51中的name值,等於b
  • 這裡,a和b的Stack值都指向同一Heap地址ADDR 51,所以無論對那個進行操作,都是對一個東西做操作,所以會互相影響

資料型別面試題_5

相關文章