天天看點

C/C++,Java,Python記憶體管理

轉載至http://hackerxu.com/2015/01/13/ram.html,轉載前請與原作者聯系。

記憶體管理

C

在C語言中,記憶體主要分為如下5個存儲區:

棧(Stack):位于函數内的局部變量(包括函數實參),由編譯器負責配置設定釋放,函數結束,棧變量失效。

堆(Heap):由程式員用malloc/calloc/realloc配置設定,free釋放。如果程式員忘記free了,則會造成記憶體洩露,程式結束時該片記憶體會由OS回收。

全局區/靜态區(Global Static Area): 全局變量和靜态變量存放區,程式一經編譯好,該區域便存在。并且在C語言中初始化的全局變量和靜态變量和未初始化的放在相鄰的兩個區域(在C++中,由于全局變量和靜态變量編譯器會給這些變量自動初始化指派,是以沒有區分了)。由于全局變量一直占據記憶體空間且不易維護,推薦少用。程式結束時釋放。

C風格字元串常量存儲區: 專門存放字元串常量的地方,程式結束時釋放。

程式代碼區:存放程式二進制代碼的區域。

簡單來說, c 并沒有記憶體管理,完全是靠程式員手動釋放和申請的.

C++

在C++語言中,與C類似,不過也有所不同,記憶體主要分為如下5個存儲區:

棧(Stack):位于函數内的局部變量(包括函數實參),由編譯器負責配置設定釋放,函數結束,棧變量失效。

堆(Heap):這裡與C不同的是,該堆是由new申請的記憶體,由delete或delete[]負責釋放

自由存儲區(Free Storage):由程式員用malloc/calloc/realloc配置設定,free釋放。如果程式員忘記free了,則會造成記憶體洩露,程式結束時該片記憶體會由OS回收。

全局區/靜态區(Global Static Area): 全局變量和靜态變量存放區,程式一經編譯好,該區域便存在。在C++中,由于全局變量和靜态變量編譯器會給這些變量自動初始化指派,是以沒有區分了初始化變量和未初始化變量了。由于全局變量一直占據記憶體空間且不易維護,推薦少用。程式結束時釋放。

常量存儲區: 這是一塊比較特殊的存儲區,專門存儲不能修改的常量(如果采用非正常手段更改當然也是可以的了)。

C++為了能相容 C,對記憶體機制也是一個悲劇~

Java

 對于Java程式員來說,在虛拟機的自動記憶體管理機制的幫助下,不再需要為每一個new操作去寫配對的delete/free代碼,而且不容易出現記憶體洩漏和記憶體溢出問題,看起來由虛拟機管理記憶體一切都很美好。不過,也正是因為Java程式員把記憶體控制的權力交給了Java虛拟機,一旦出現記憶體洩漏和溢出方面的問題,如果不了解虛拟機是怎樣使用記憶體的,那排查錯誤将會成為一項異常艱難的工作。  

java 的記憶體管理:

程式運作前:JVM向作業系統請求一定的記憶體空間,稱為初始記憶體空間!程式執行過程中所需的記憶體都是由java虛拟機從這片記憶體空間中劃分的。

程式運作中:java程式一直向java虛拟機申請記憶體,當程式所需要的記憶體空間超出初始記憶體空間時,java虛拟機會再次向作業系統申請更多的記憶體供程式使用!

記憶體溢出:程式接着運作,當java虛拟機已申請的記憶體達到了規定的最大記憶體空間,但程式還需要更多的記憶體,這時會出現記憶體溢出的錯誤!

記憶體空間邏輯劃分:

方法區:方法區預設最大容量為64M,Java虛拟機會将加載的java類存入方法區,儲存類的結構(屬性與方法),類靜态成員等内容。

堆:預設最大容量為64M,堆存放對象持有的資料,同時保持對原類的引用。可以簡單的了解為對象屬性的值儲存在堆中,對象調用的方法儲存在方法區。

棧:棧預設最大容量為1M,在程式運作時,每當遇到方法調用時,Java虛拟機就會在棧中劃分一塊記憶體稱為棧幀(Stack frame),棧幀中的記憶體供局部變量(包括基本類型與引用類型)使用,當方法調用結束後,Java虛拟機會收回此棧幀占用的記憶體。

java的記憶體管理使用的是垃圾回收機制,具體的垃圾回收政策可以 google 一下,它有一系列變化,展開又是一片博文了.

python

Python的記憶體管理機制可以從三個方面來講:

引用計數

垃圾回收

記憶體池機制

1 引用計數

Python采用了類似Windows核心對象一樣的方式來對記憶體進行管理。每一個對象,都維護這一個對指向該對對象的引用的計數。

例如:

x = 3.14

y = x

這裡的’引用’其實和 c 中的指針意義相近,如果了解 c 指針,那麼就不難了解 python 的引用機制.這裡的 x和 y 其實指向的是同一個對象3.14.

2 垃圾回收

python不像C++,Java等語言一樣,他們可以不用事先聲明變量類型而直接對變量進行指派。對Python語言來講,對象的類型和記憶體都是在運作時确定的。這也是為什麼我們稱Python語言為動态類型的原因(這裡我們把動态類型可以簡單的歸結為對變量記憶體位址的配置設定是在運作時自動判斷變量類型并對變量進行指派)。

3 記憶體池機制

Python的記憶體機制以金字塔行,-1,-2層主要有作業系統進行操作,

第0層是C中的malloc,free等記憶體配置設定和釋放函數進行操作;

第1層和第2層是記憶體池,有Python的接口函數PyMem_Malloc函數實作,當對象小于256K時有該層直接配置設定記憶體;

第3層是最上層,也就是我們對Python對象的直接操作;

在 C 中如果頻繁的調用 malloc 與 free 時,是會産生性能問題的.再加上頻繁的配置設定與釋放小塊的記憶體會産生記憶體碎片. Python 在這裡主要幹的工作有:

如果請求配置設定的記憶體在1~256位元組之間就使用自己的記憶體管理系統,否則直接使用 malloc.

這裡還是會調用 malloc 配置設定記憶體,但每次會配置設定一塊大小為256k的大塊記憶體.

  經由記憶體池登記的記憶體到最後還是會回收到記憶體池,并不會調用 C 的 free 釋放掉.以便下次使用.對于簡單的Python對象,例如數值、字元串,元組(tuple不允許被更改)采用的是複制的方式(深拷貝?),也就是說當将另一個變量B指派給變量A時,雖然A和B的記憶體空間仍然相同,但當A的值發生變化時,會重新給A配置設定空間,A和B的位址變得不再相同