1. 程式人生 > >作業系統分配記憶體

作業系統分配記憶體

計算機體系結構和記憶體層次

作業系統中記憶體的最小訪問單位是 位元組 ,也就是8bit。

通常我們所說的計算機系統是32位的匯流排,所謂的32位匯流排就是說一次讀寫可以從記憶體當中讀或者寫32位(也就是4位元組)。

因為一次讀寫是32位,所以需要地址對齊,訪問的時候不能從任意地方開始。

在CPU中可以看到快取記憶體,由於指令執行和訪問資料都需要從記憶體裡讀資料,如果此時有大量資料要讀寫而且會重複利用的話,那麼在CPU中加快取記憶體會使讀寫進行得更快。

有了這樣一個大致瞭解,可以來看記憶體層次結構。

首先CPU在讀寫指令和資料的時候,如果快取裡已經有相應的內容,那麼CPU直接從快取中拿到資料,這時候速度是最快的。(寫程式的時候完全感受不到L1快取和L2快取的存在,因為這部分是硬體控制的,不能顯示使用它們。)

如果快取不命中,那麼就必須去記憶體中讀。如果記憶體還是沒找到,那就去外存中讀。(訪問速度又有很大差別)

雖然計算機硬體一直在飛速發展,記憶體容量也在不斷增長,但是仍然不可能將所有使用者程序和系統所需要的全部程式和資料放入主存中,所以作業系統就要對記憶體進行合理地劃分和有效地動態分配。作業系統需要做到四個方面:抽象、保護、共享和虛擬化。

如圖,四個程序在作業系統的劃分和管理下,彼此之間在邏輯上既需要相互獨立,又可以相互通訊。

作業系統中採用的記憶體管理方式有:

  • 重定位(relocation)
  • 分段(segmentation)
  • 分頁(paging)
  • 虛擬儲存(virtual memory)

目前多數系統(如 Linux)採用按需頁式虛擬儲存。

地址空間和地址生成

實體地址空間——硬體支援的地址空間,起始地址從0直到MAXsys。這個編號在儲存單元角度來講是唯一的,但是這種唯一對於我們寫程式來說是不大容易的,因為我們在寫程式的時候對於到底要使用哪個地址可能是不知道的。

邏輯地址空間——在CPU執行的程序看到的地址,起始地址從0知道MAXprog。對應的是可執行檔案的那段空間。

對於我們用高階語言編寫的程式,經過如下過程生成它的邏輯地址:

此時的邏輯地址生成時機的不同會有不同的限制。

  • 編譯時:已經假設起始地址已知,如果起始地址改變,必須重新編譯。例如以前的手機,程式是寫死的,不能自己安裝應用,只能用手機裡編譯好的。
  • 載入時:如編譯時起始位置未知,編譯器需生成可重定位的程式碼。例如現在的智慧手機,可以下載很多APP。
  • 執行時:執行時程式碼可移動,但需地址轉換(對映)硬體支援。這種情況出現在使用虛擬儲存的系統,

邏輯地址生成後,接著就是生成實體地址,過程如下:

因為記憶體有著諸多限制,所以也有著對應的檢查機制。檢查過程如圖:

連續地址分配

生成地址後接著分配地址,連續記憶體分配是給程序分配一塊不小於指定大小的連續的實體記憶體區域。地址分配從兩個角度考慮:如何去找你要用的空間分割槽;如何處理不能利用的小的空閒分割槽。

這裡不能利用的小的空閒分割槽我們統稱為 記憶體碎片 ,記憶體碎片分為三類:

  • 記憶體碎片:有的還可以用,有的無論如何都用不起來了。
  • 外部碎片:分配單元之間的未被使用記憶體
  • 內部碎片:分配單元內部的未被使用記憶體(你只佔500位元組,但是不得不分配512位元組)

這裡我們就不得不有所取捨地選擇不同的分配策略,常用的有三種:最先匹配(First-fit)、最佳匹配(Best-fit)、最差匹配(Worst-fit)。

最先匹配(First Fit Allocation)策略

原理 & 實現:

  • 空閒分割槽列表按地址順序排序
  • 分配過程時,搜尋一個合適的分割槽
  • 釋放分割槽時,檢查是否可與臨近的空閒分割槽合併

優點:

  • 簡單(這也算優點的話)
  • 在高地址空間有大塊的空閒分割槽

缺點:

  • 外部碎片
  • 分配大塊時較慢

最佳匹配(Best Fit Allocation)策略

原理 & 實現:

  • 空閒分割槽列表按照大小排序
  • 分配時,查詢一個合適的分割槽
  • 釋放時,查詢並且合併臨近的空閒分割槽(如果找到)

優點:

  • 大部分分配的尺寸較小時,效果很好(可避免大的空閒分割槽被拆分)
  • 可減小外部碎片的大小

缺點:

  • 外部碎片
  • 釋放分割槽緩慢
  • 容易產生很多無用的小碎片

最差匹配(Worst Fit Allocation)策略

原理 & 實現:

  • 空閒分割槽列表按由大到小排序
  • 分配時,選最大的分割槽
  • 釋放時,檢查是否可與臨近的空閒分割槽合併,進行可能的合併,並調整空閒分割槽列表順序

優點:

  • 中等大小的分配較多時,效果最好
  • 避免出現太多的小碎片

缺點:

  • 釋放分割槽較慢
  • 外部碎片
  • 容易破壞大的空閒分割槽,因此後續難以分配大的分割槽

碎片整理

通過調整程序佔用的分割槽位置來減少或避免分割槽碎片

  1. 緊湊(compaction) 通過移動分配給程序的記憶體分割槽,以合併外部碎片。緊湊的條件是:所有的應用程式可動態重定位。

  2. 分割槽對換(Swapping in/out) 通過搶佔並回收處於等待狀態程序的分割槽,以增大可用記憶體空間。

夥伴系統(Buddy System)

夥伴系統即,整個可分配的分割槽大小2^U,需要的分割槽大小為2^(U-1) < s ≤ 2^U 時,把整個塊分配給該程序。

  記憶體是計算機中最重要的資源之一,通常情況下,實體記憶體無法容納下所有的程序。雖然實體記憶體的增長現在達到了N個GB,但比實體記憶體增長還快的是程式,所以無論實體記憶體如何增長,都趕不上程式增長的速度,所以作業系統如何有效的管理記憶體便顯得尤為重要。本文講述作業系統對於記憶體的管理的過去和現在,以及一些頁替換的演算法的介紹。

對於程序的簡單介紹

    在開始之前,首先從作業系統的角度簡單介紹一下程序。程序是佔有資源的最小單位,這個資源當然包括記憶體。在現代作業系統中,每個程序所能訪問的記憶體是互相獨立的(一些交換區除外)。而程序中的執行緒所以共享程序所分配的記憶體空間。

    在作業系統的角度來看,程序=程式+資料+PCB(程序控制塊)。這個概念略微有點抽象,我通過一個類比來說吧:比如,你正在廚房做飯,你一邊看著菜譜一邊按照菜譜將原料做成菜,就在這時,你兒子進來告訴你他擦破了腿,此時你停下手中的工作,將菜譜反扣過來,然後找來急救書按照書中的內容給你兒子貼上創口貼,貼完後你繼續回去開啟菜譜,然後繼續做飯。在這個過程中,你就好比CPU,菜譜就好比程式,而做菜的原料就好比資料。你按照程式指令加工資料,而急救工作好比一個更高優先順序的程序,中斷了你當前做飯的工作,然後你將菜譜反扣過來(保護現場),轉而去處理高優先順序的程序,處理完畢後你繼續從剛才的頁讀菜譜(恢復現場),然後繼續執行做菜這個程序。

    在簡單介紹完程序的概念後,我們來轉入記憶體。

沒有記憶體抽象的年代

    在早些的作業系統中,並沒有引入記憶體抽象的概念。程式直接訪問和操作的都是實體記憶體。比如當執行如下指令時:

mov reg1,1000

    這條指令會毫無想象力的將實體地址1000中的內容賦值給暫存器。不難想象,這種記憶體操作方式使得作業系統中存在多程序變得完全不可能,比如MS-DOS,你必須執行完一條指令後才能接著執行下一條。如果是多程序的話,由於直接操作實體記憶體地址,當一個程序給記憶體地址1000賦值後,另一個程序也同樣給記憶體地址賦值,那麼第二個程序對記憶體的賦值會覆蓋第一個程序所賦的值,這回造成兩條程序同時崩潰。

    沒有記憶體抽象對於記憶體的管理通常非常簡單,除去作業系統所用的記憶體之外,全部給使用者程式使用。或是在記憶體中多留一片區域給驅動程式使用,如圖1所示。

    1

    圖1.沒有記憶體抽象時,對記憶體的使用

    第一種情況作業系統存於RAM中,放在記憶體的低地址,第二種情況作業系統存在於ROM中,存在記憶體的高地址,一般老式的手機作業系統是這麼設計的。

    如果這種情況下,想要作業系統可以執行多程序的話,唯一的解決方案就是和硬碟搞交換,當一個程序執行到一定程度時,整個存入硬碟,轉而執行其它程序,到需要執行這個程序時,再從硬碟中取回記憶體,只要同一時間記憶體中只有一個程序就行,這也就是所謂的交換(Swapping)技術。但這種技術由於還是直接操作實體記憶體,依然有可能引起程序的崩潰。

    所以,通常來說,這種記憶體操作往往只存在於一些洗衣機,微波爐的晶片中,因為不可能有第二個程序去徵用記憶體。

記憶體抽象

    在現代的作業系統中,同一時間執行多個程序是再正常不過的了。為了解決直接操作記憶體帶來的各種問題,引入的地址空間(Address Space),這允許每個程序擁有自己的地址。這還需要硬體上存在兩個暫存器,基址暫存器(base register)和界址暫存器(limit register),第一個暫存器儲存程序的開始地址,第二個暫存器儲存上界,防止記憶體溢位。在記憶體抽象的情況下,當執行

mov reg1,20

    這時,實際操作的實體地址並不是20,而是根據基址和偏移量算出實際的實體地址程序操作,此時操作的實際地址可能是:

mov reg1,16245

    在這種情況下,任何操作虛擬地址的操作都會被轉換為操作實體地址。而每一個程序所擁有的記憶體地址是完全不同的,因此也使得多程序成為可能。

    但此時還有一個問題,通常來說,記憶體大小不可能容納下所有併發執行的程序。因此,交換(Swapping)技術應運而生。這個交換和前面所講的交換大同小異,只是現在講的交換在多程序條件下。交換的基本思想是,將閒置的程序交換出記憶體,暫存在硬碟中,待執行時再交換回記憶體,比如下面一個例子,當程式一開始時,只有程序A,逐漸有了程序B和C,此時來了程序D,但記憶體中沒有足夠的空間給程序D,因此將程序B交換出記憶體,分給程序D。如圖2所示。

    2

    圖2.交換技術

    通過圖2,我們還發現一個問題,程序D和C之間的空間由於太小無法另任何程序使用,這也就是所謂的外部碎片。一種方法是通過緊湊技術(Memory Compaction)解決,通過移動程序在記憶體中的地址,使得這些外部碎片空間被填滿。還有一些討巧的方法,比如記憶體整理軟體,原理是申請一塊超大的記憶體,將所有程序置換出記憶體,然後再釋放這塊記憶體,從而使得從新載入程序,使得外部碎片被消除。這也是為什麼執行完記憶體整理會狂讀硬碟的原因。另外,使用緊湊技術會非常消耗CPU資源,一個2G的CPU沒10ns可以處理4byte,因此多一個2G的記憶體進行一次緊湊可能需要好幾秒的CPU時間。

    上面的理論都是基於程序所佔的記憶體空間是固定的這個假設,但實際情況下,程序往往會動態增長,因此建立程序時分配的記憶體就是個問題了,如果分配多了,會產生內部碎片,浪費了記憶體,而分配少了會造成記憶體溢位。一個解決方法是在程序建立的時候,比程序實際需要的多分配一點記憶體空間用於程序的增長。一種是直接多分配一點記憶體空間用於程序在記憶體中的增長,另一種是將增長區分為資料段和棧(用於存放返回地址和區域性變數),如圖3所示。

    3

    圖3.建立程序時預留空間用於增長

    當預留的空間不夠滿足增長時,作業系統首先會看相鄰的記憶體是否空閒,如果空閒則自動分配,如果不空閒,就將整個程序移到足夠容納增長的空間記憶體中,如果不存在這樣的記憶體空間,則會將閒置的程序置換出去。

     當允許程序動態增長時,作業系統必須對記憶體進行更有效的管理,作業系統使用如下兩種方法之一來得知記憶體的使用情況,分別為1)點陣圖(bitmap) 2)連結串列

     使用點陣圖,將記憶體劃為多個大小相等的塊,比如一個32K的記憶體1K一塊可以劃為32塊,則需要32位(4位元組)來表示其使用情況,使用點陣圖將已經使用的塊標為1,位使用的標為0.而使用連結串列,則將記憶體按使用或未使用分為多個段進行連結,這個概念如圖4所示。

    4

     圖4.點陣圖和連結串列表示記憶體的使用情況

     使用連結串列中的P表示程序,從0-2是程序,H表示空閒,從3-4表示是空閒。

     使用位圖表示記憶體簡單明瞭,但一個問題是當分配記憶體時必須在記憶體中搜索大量的連續0的空間,這是十分消耗資源的操作。相比之下,使用連結串列進行此操作將會更勝一籌。還有一些作業系統會使用雙向連結串列,因為當程序銷燬時,鄰接的往往是空記憶體或是另外的程序。使用雙向連結串列使得連結串列之間的融合變得更加容易。

    還有,當利用連結串列管理記憶體的情況下,建立程序時分配什麼樣的空閒空間也是個問題。通常情況下有如下幾種演算法來對程序建立時的空間進行分配。

  •      臨近適應演算法(Next fit)---從當前位置開始,搜尋第一個能滿足程序要求的記憶體空間
  •      最佳適應演算法(Best fit)---搜尋整個連結串列,找到能滿足程序要求最小記憶體的記憶體空間
  •      最大適應演算法(Wrost fit)---找到當前記憶體中最大的空閒空間
  •      首次適應演算法(First fit) ---從連結串列的第一個開始,找到第一個能滿足程序要求的記憶體空間

虛擬記憶體(Virtual Memory)

    虛擬記憶體是現代作業系統普遍使用的一種技術。前面所講的抽象滿足了多程序的要求,但很多情況下,現有記憶體無法滿足僅僅一個大程序的記憶體要求(比如很多遊戲,都是10G+的級別)。在早期的作業系統曾使用覆蓋(overlays)來解決這個問題,將一個程式分為多個塊,基本思想是先將塊0加入記憶體,塊0執行完後,將塊1加入記憶體。依次往復,這個解決方案最大的問題是需要程式設計師去程式進行分塊,這是一個費時費力讓人痛苦不堪的過程。後來這個解決方案的修正版就是虛擬記憶體。

    虛擬記憶體的基本思想是,每個程序有用獨立的邏輯地址空間,記憶體被分為大小相等的多個塊,稱為(Page).每個頁都是一段連續的地址。對於程序來看,邏輯上貌似有很多記憶體空間,其中一部分對應實體記憶體上的一塊(稱為頁框,通常頁和頁框大小相等),還有一些沒載入在記憶體中的對應在硬碟上,如圖5所示。

    5

    圖5.虛擬記憶體和實體記憶體以及磁碟的對映關係

    由圖5可以看出,虛擬記憶體實際上可以比實體記憶體大。當訪問虛擬記憶體時,會訪問MMU(記憶體管理單元)去匹配對應的實體地址(比如圖5的0,1,2),而如果虛擬記憶體的頁並不存在於實體記憶體中(如圖5的3,4),會產生缺頁中斷,從磁碟中取得缺的頁放入記憶體,如果記憶體已滿,還會根據某種演算法將磁碟中的頁換出。

    而虛擬記憶體和實體記憶體的匹配是通過頁表實現,頁表存在MMU中,頁表中每個項通常為32位,既4byte,除了儲存虛擬地址和頁框地址之外,還會儲存一些標誌位,比如是否缺頁,是否修改過,防寫等。可以把MMU想象成一個接收虛擬地址項返回實體地址的方法。

    因為頁表中每個條目是4位元組,現在的32位作業系統虛擬地址空間會是2的32次方,即使每頁分為4K,也需要2的20次方*4位元組=4M的空間,為每個程序建立一個4M的頁表並不明智。因此在頁表的概念上進行推廣,產生二級頁表,二級頁表每個對應4M的虛擬地址,而一級頁表去索引這些二級頁表,因此32位的系統需要1024個二級頁表,雖然頁表條目沒有減少,但記憶體中可以僅僅存放需要使用的二級頁表和一級頁表,大大減少了記憶體的使用。

頁面替換演算法

因為在計算機系統中,讀取少量資料硬碟通常需要幾毫秒,而記憶體中僅僅需要幾納秒。一條CPU指令也通常是幾納秒,如果在執行CPU指令時,產生幾次缺頁中斷,那效能可想而知,因此儘量減少從硬碟的讀取無疑是大大的提升了效能。而前面知道,實體記憶體是極其有限的,當虛擬記憶體所求的頁不在實體記憶體中時,將需要將實體記憶體中的頁替換出去,選擇哪些頁替換出去就顯得尤為重要,如果演算法不好將未來需要使用的頁替換出去,則以後使用時還需要替換進來,這無疑是降低效率的,讓我們來看幾種頁面替換演算法。

最佳置換演算法(Optimal Page Replacement Algorithm)

     最佳置換演算法是將未來最久不使用的頁替換出去,這聽起來很簡單,但是無法實現。但是這種演算法可以作為衡量其它演算法的基準。

最近不常使用演算法(Not Recently Used Replacement Algorithm)

     這種演算法給每個頁一個標誌位,R表示最近被訪問過,M表示被修改過。定期對R進行清零。這個演算法的思路是首先淘汰那些未被訪問過R=0的頁,其次是被訪問過R=1,未被修改過M=0的頁,最後是R=1,M=1的頁。

先進先出頁面置換演算法(First-In,First-Out Page Replacement Algorithm)

    這種演算法的思想是淘汰在記憶體中最久的頁,這種演算法的效能接近於隨機淘汰。並不好。

改進型FIFO演算法(Second Chance Page Replacement Algorithm)

這種演算法是在FIFO的基礎上,為了避免置換出經常使用的頁,增加一個標誌位R,如果最近使用過將R置1,當頁將會淘汰時,如果R為1,則不淘汰頁,將R置0.而那些R=0的頁將被淘汰時,直接淘汰。這種演算法避免了經常被使用的頁被淘汰。

時鐘替換演算法(Clock Page Replacement Algorithm)

    雖然改進型FIFO演算法避免置換出常用的頁,但由於需要經常移動頁,效率並不高。因此在改進型FIFO演算法的基礎上,將佇列首位相連形成一個環路,當缺頁中斷產生時,從當前位置開始找R=0的頁,而所經過的R=1的頁被置0,並不需要移動頁。如圖6所示。

    6

    圖6.時鐘置換演算法

最久未使用演算法(LRU Page Replacement Algorithm)

    LRU演算法的思路是淘汰最近最長未使用的頁。這種演算法效能比較好,但實現起來比較困難。

下面表是上面幾種演算法的簡單比較:

演算法 描述
最佳置換演算法 無法實現,最為測試基準使用
最近不常使用演算法 和LRU效能差不多
先進先出演算法 有可能會置換出經常使用的頁
改進型先進先出演算法 和先進先出相比有很大提升
最久未使用演算法 效能非常好,但實現起來比較困難
時鐘置換演算法 非常實用的演算法

    上面幾種演算法或多或少有一些區域性性原理的思想。區域性性原理分為時間和空間上的區域性性

    1.時間上,最近被訪問的頁在不久的將來還會被訪問。

    2.空間上,記憶體中被訪問的頁周圍的頁也很可能被訪問。


相關推薦

作業系統分配記憶體

計算機體系結構和記憶體層次 作業系統中記憶體的最小訪問單位是 位元組 ,也就是8bit。 通常我們所說的計算機系統是32位的匯流排,所謂的32位匯流排就是說一次讀寫可以從記憶體當中讀或者寫32位(也就是4位元組)。 因為一次讀寫是32位,所以需要地址對齊,訪問的時候

作業系統記憶體離散分配

儲存管理的離散分配方式 基本分頁儲存管理方式   1)頁面的概念 記憶體劃分成多個小單元,每個單元K大小,稱(物理)塊。作業也按K單位大小劃分成片,稱為頁面。① 物理劃分塊的大小 = 邏輯劃分的頁的大小②頁面大小要適中。 太大,(最後一頁)內碎片增大,類似連續分配的問題。 太小的話,頁

作業系統可變分割槽用C語言實現按首次適應演算法分配記憶體

每個分割槽有4個數據項,起始地址,大小,狀態,程序號,其實地址和大小以KB為單位,狀態分為“已分”或“空閒”,程序號:若分割槽是已分,則填上此分割槽的程序號,若分割槽是空閒,則填入? 這裡先採用首次適應演算法,首次適應演算法是將空閒區按起始地址從小到大排序後,

作業系統可變分割槽用C語言實現按最佳適應演算法分配記憶體

類似上一篇部落格,在分配記憶體使用最佳使用演算法,即將空閒區按大小進行排序實現 #include<stdio.h> #include<stdlib.h> #include<string.h> typedef struc

作業系統常見記憶體分配演算法及優缺點

常見記憶體分配演算法及優缺點如下:  (1)首次適應演算法。使用該演算法進行記憶體分配時,從空閒分割槽鏈首開始查詢,直至找到一個能滿足其大小需求的空閒分割槽為止。然後再按照作業的大小,從該分割槽中劃出一塊記憶體分配給請求者,餘下的空閒分割槽仍留在空閒分割槽鏈中。  該演算法

作業系統記憶體分配

首先看一下“基本的儲存分配方式”種類:        1.  離散分配方式的出現 由於連續分配方式會形成許多記憶體碎片,雖可通過“緊湊”功能將碎片合併,但會付出很大開銷。於是出現離散分配方式:將一個程序直接分散地裝入到許多不相鄰的記憶體分割槽中。      

c語言獲得動態分配記憶體後的陣列記憶體大小

c語言獲得動態分配記憶體後的陣列記憶體大小 用一個函式 :_msize(); ★注意:該函式為Windows獨有★ int* s = (int*)malloc(sizeof(int));     int i;     for(i

關於書上說的“編譯的時候分配記憶體

關於書上說的“編譯的時候分配記憶體” 一下均為網路上收集的資料: 1、所謂在編譯期間分配空間指的是靜態分配空間(相對於用new動態申請空間),如全域性變數或靜態變數(包括一些複雜型別的常量),它們所需要的空間大小可以 明確計算出來,並且不會再改變,因此它們可以直接存放在可執行檔案的特定的節裡

處理new分配記憶體失敗情況

轉自:http://www.51testing.com/html/70/n-827070.html 在C++語言中,我們經常會使用new給一個物件分配記憶體空間,而當記憶體不夠會出現記憶體不足的情況。C++提供了兩中報告方式:   1、丟擲bad_alloc異常來報告分配失敗;   2、返回空指標,而不

C儲存類、連結和記憶體管理--動態分配記憶體及型別限定詞

文章目錄 儲存類說明符 儲存類和函式 動態分配記憶體 `malloc`函式 `free`函式 `calloc`函式 動態分配記憶體的缺點 C型別限定關鍵字

c語言動態分配記憶體記憶體分配部分函式

#include<stdio.h> /** 在C中動態分配記憶體的基本步驟有: 1,用malloc類的函式分配記憶體; 2,用這些記憶體支援應用程式 3,用free函式釋放記憶體 二、動態記憶體分配函式     malloc :從堆上分配記憶體 &nbs

matlab執行出現“變數似乎會隨著迭代次數改變而變化,請預分配記憶體,以提高執行速度”問題

這句話大致意思就是: b = 0;for i = 1:3    a(i) = b;end是說變數的長度是變化的,經常在迴圈裡出現,比如上面這個例子,這樣會影響計算速度,最好的辦法是預先定義a的長度,比如b = 0;a = zeros(1,3);for i = 1:3  &nbs

C++ Primer Plus書之--C++指標及使用new分配記憶體,使用delete釋放記憶體

先來個簡單的程式初步認識一下指標  #include "iostream" using namespace std; int main() { // 定義一個int型變數 int num = 123; // 定義一個int型指標變數 int * p_num; // 指標指向

jvm對大物件分配記憶體的特殊處理

    前段日子在和leader交流技術的時候,偶然聽到jvm在分配記憶體空間給大物件時,如果young區空間不足會直接在old區切一塊過去。對於這個結論很好奇,也比較懷疑,所以就上網搜了下,發現還真有這麼回事。所謂的大物件是指,需要大量連續記憶體空間的Java物件,最典型的大物

淺談結構體如何分配記憶體

下面直接以例子進行說明: (1)先是定義瞭如下結構體: struct{ char a; int i; double d; }text; 然後用sizeof(text),預期結果是1+2+8 = 11???如果這樣想就錯了,答案是16. (2)然後,換一下變數的順序:

計算機作業系統(六)--- 記憶體 磁碟

DRAM 和 SRAM        隨機訪問器儲存器(Random-Access Memory ,RAM) 分為兩類 : 靜態和動態.        這兩個的區別可以見下面這樣圖:

Chapter9.4 陣列的替代品 向量容器vector,是一個快速的動態分配記憶體的陣列

1.動態陣列,可以在執行階段設定長度;而靜態陣列的長度是常量; 2.向量容器vector具有陣列的快速索引方式; 3.可以插入和刪除元素; 向量容器vector的定義和初始化 vector<double>vec1; /**向量容器的名稱是vec1,裡面放置double型別

為物件動態分配記憶體

如果類中的資料成員含有指標變數,就需要為指標變數分配動態記憶體。(通常在程式設計中,應該儘量避免使用指標,應該用容器替代指標) 在本例中,使用二重指標,可以視為一個二維陣列,不過該陣列的元素個數可變。 如下為為指標分配空間的建構函式; //建構函式,建立一個可以指定長度和高度的二維陣列

Linux分配記憶體的時候記憶體不足異常處理

本文作者:禹明明,叩丁狼高階講師。原創文章,轉載請註明出處。  在linux上部署專案的時候可能會遇到這麼一個錯誤 Native memory allocation (mmap) failed to map 1879048192 bytes for committing

雜湊桶的預分配記憶體的實現形式

之前在書本中使用過的hashtable的時候,總體思想是使用一大片記憶體,然後把key值hash成一個int,找到對應的記憶體的結構的位置,然後找到相應的資料。常用的解決衝突的方式是,需要進行拉鍊,再new一個新結點來表示資料。這是一種實現形式,邏輯上沒有什麼問題。 總體方