Python int 數據數據類型在內存中分配原理

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個字節

 

 執行結果

 

 

 關於內存地址的理解如下

電腦的內存(尤其是指主存)是由許多“內存地址”所組成的,每個內存地址都有一個“物理地址”,能供CPU(或其他設備)訪問。一般,只有如BIOS操作系統及部分特定之公用軟件(如內存測試軟件)等系統軟件,能使用機器碼的運算對象或寄存器對物理地址定址,指示CPU要求內存控制器之類的硬件設備,使用內存總線或系統總線,亦或分別之控制總線地址總線數據總線,運行該程序之命令。內存控制器的總線是由數條並行的線路所組成的,每條線路表示一個比特。總線的寬度因此依電腦不同,決定了可定址之存儲單位數量,以及每一單位內的比特數量。
計算機程序使用內存地址來運行機器碼、存儲及截取數據。大多數的應用程序無法得知實際的物理地址,而是使用電腦的內存管理單元及操作系統的內存映射,爲“邏輯地址”或虛擬地址定址
 
內存地址0x0001和內存地址0x0002之間差的是一個byte,而不是一個bit?
下內存的物理構造,一般內存的外形圖片如圖1。一個內存是由若干個黑色的內存顆粒構成的。每一個內存顆粒叫做一個chip。
 
圖1.內存外形圖

 

 

上面這個內存條有8個chip。每一個chip內部,是由8個bank組成的。其構造如下圖:
 
圖2.內存顆粒物理結構

 

 

在每個bank內部,就是電容的行列矩陣結構了。(注意,二維矩陣中的一個元素一般存儲着8個bit,也就是說包含了8個小電容)。
 
圖3.bank物理結構

 

8個同位置的元素,一起組成在內存中連續的64個bit。如下圖
 
圖4.jpg

通過內存的物理結構我們可以看出,因爲在內存中最小單位就是字節。所以操作系統在管理它的時候,最小單位也就是字節了。另外,通過上述的我們還有一個額外發現。那就是在內存中連續的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。

也就是說 arena > pool > block,感覺很像俄羅斯套娃吧。
爲了避免頻繁調用 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 只有以下三種狀態。

  1. 已經分配
  2. 使用完畢
  3. 未使用

第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字節的內存空間

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章