python代碼如下
import sys for i in "abcdefghijkdfasdf;;lblcv": byte_list = bytes(i, encoding="utf-8") print('*' * 11, byte_list) for k in byte_list: print(type(k)) print(sys.getsizeof(k)) # print(bin(k)) print(hex(id(k)))
bytes函數將字符串按照encoding 將字符串轉換爲字節序列;
utf-8中一個英文字母佔1個字節
執行結果
關於內存地址的理解如下
上面這個內存條有8個chip。每一個chip內部,是由8個bank組成的。其構造如下圖:
在每個bank內部,就是電容的行列矩陣結構了。(注意,二維矩陣中的一個元素一般存儲着8個bit,也就是說包含了8個小電容)。
8個同位置的元素,一起組成在內存中連續的64個bit。如下圖
通過內存的物理結構我們可以看出,因爲在內存中最小單位就是字節。所以操作系統在管理它的時候,最小單位也就是字節了。另外,通過上述的我們還有一個額外發現。那就是在內存中連續的64個bit,其實在內存的物理結構中,並不連續。而是分散在同位置的8個rank上的。
計算機的存儲空間比作一本空白的短篇小說。頁面上還沒有任何內容。最終,會有不同的作者出現。每個作者都需要一些空間來寫他們的故事。
由於不允許彼此書寫,因此必須注意他們能書寫的頁面。開始書寫之前,請先諮詢書籍管理員。然後,管理員決定允許他們在書中寫什麼。
如果這書已經存在很長時間了,因此其中的許多故事都不再適用。當沒有人閱讀或引用故事時,它們將被刪除以爲新故事騰出空間。
本質上,計算機內存就像一本空書。實際上,調用固定長度的連續內存頁面塊是很常見的,因此這種類比非常適用。
作者就像需要將數據存儲在內存中的不同應用程序或進程。決定作者在書中書寫位置的管理員就像是各種存儲器管理的角色,刪除舊故事爲新故事騰出空間的人是垃圾收集者(garbage collector)。
內存管理是應用程序讀取和寫入數據的過程。內存管理器確定將應用程序數據放置在何處。
由於內存有限,類比書中的頁面一樣,管理員必須找到一些可用空間並將其提供給應用程序。提供內存的過程通常稱爲內存分配。
其實如果我們瞭解內存管理機制,以更快、更好的方式解決問題。
Python 語音中 一切皆對象,Python對象實現的核心就是一個結構體--PyObject
PyObject是每個對象必有的內容,可以說是Python中所有對象的祖父,僅包含兩件事:
- ob_refcnt:引用計數(reference count)
- ob_type:指向另一種類型的指針(pointer to another type)
Python將部分內存用於內部使用和非對象內存。另一部分專用於對象存儲(您的int,dict等)
Python的內存分配器
內存結構
在Python中,當要分配內存空間時,不單純使用 malloc/free,而是在其基礎上堆放3個獨立的分層,有效率地進行分配。
[圖片上傳失敗...(image-22ef57-1588088246750)]
第 0 層往下是 OS 的功能。第 -2 層是隱含和機器的物理性相關聯的部分,OS 的虛擬內 存管理器負責這部分功能。第 -1 層是與機器實際進行交互的部分,OS 會執行這部分功能。 因爲這部分的知識已經超出了本書的範圍,我們就不額外加以說明了。
在第 3 層到第 0 層調用了一些具有代表性的函數,其調用圖如下。
[圖片上傳失敗...(image-8142ba-1588088246750)]
第0層 通用的基礎分配器
以 Linux 爲例,第 0 層指的就是 glibc 的 malloc() 這樣的分配器,是對 Linux 等 OS 申 請內存的部分。
Python 中並不是在生成所有對象時都調用 malloc(),而是根據要分配的內存大小來改 變分配的方法。申請的內存大小如果大於 256 字節,就老實地調用 malloc();如果小於等 於 256 字節,就要輪到第 1 層和第 2 層出場了
第1層處理的信息的內存結構
根據所管理的內存空間的作用和大小的不同,我們稱最小 的單位爲 block,最終返回給申請者的就是這個 block 的地址。比 block 大的單位的是 pool, pool 內部包含 block。pool 再往上叫作 arena。
爲了避免頻繁調用 malloc() 和 free(),第 0 層的分配器會以最大的單位 arena 來保留 內存。pool 是用於有效管理空的 block 的單位。
arena 這個詞有“競技場”的意思。大家可以理解成競技場裏有很多個 pool,pool 裏面漂 浮着很多個 block,這樣或許更容易理解一些。
arena
Arenas是最大的內存塊,並在內存中的頁面邊界上對齊。頁面邊界是操作系統使用的固定長度連續內存塊的邊緣。Python假設系統的頁面大小爲256 KB。
[圖片上傳失敗...(image-e2e369-1588088246750)]
Arenas內有內存池,池是一個虛擬內存頁(4 KB)。這些就像我們書中類比的頁面。這些池被分成較小的內存塊。
給定池中的所有塊均具有相同的“大小等級”。給定一定數量的請求數據,大小類定義特定的塊大小。
第1層總結
第 1 層的任務可以用一句話來總結,那就是“管理 arena”。
第2層 Python對象分配器
第 2 層的分配器負責管理 pool 內的 block。
block
pool 被分割成一個個的 block。我們在 Python 中生成對象時,最終都會被分配這個 block (在要求大小不大於 256 字節的情況下)。
以 block 爲單位來劃分,這是從 pool 初始化時就決定好的。這是因爲我們一開始利用 pool 的時候就決定了“這是供 8 字節的 block 使用的 pool”。
pool 內被 block 完全填滿了,那麼 pool 是怎麼進行 block 的狀態管理的呢?
block 只有以下三種狀態。
- 已經分配
- 使用完畢
- 未使用
第3層 對象特有的分配器
對象有列表和元組等多種多樣的型,在生成它們的時候要使用各自特有的分配器。
分配器的總結
一個內存地址所代表的永遠是1個字節,內存的每一個字節都有爲一個個編號
字節是計算機中數據處理的基本單位;1個字節=8個bit
內存地址只是一個編號,代表一個內存空間;
內存地址所執行的內存單元大小就是1字節,跟內存地址位數無關;
內存空間大小就是尋址能力,即能訪問到多少個地址
int在python裏是一個類,是不可變數據類型中的一種,一些性質和字符串是一樣的,是整型
32位系統 int:開銷= 10字節,值= 4字節 float:開銷= 8字節,value = 8字節 64位系統 int:開銷= 20字節,值= 8字節 float:開銷= 16個字節,值= 8個字節
因此,sys.getsizeof(0) 數組元素爲0。此時佔用24字節(PyObject_VAR_HEAD 的大小)。 sys.getsizeof(456) 需使用一個元素,因此多了4個字節。
綜上,一個int類型佔用了28字節,根據內存分配原則,計算機分配了32字節的內存空間