python分配內存地址
⑴ python 值相同變數名不同,內存地址相同嗎
== (雙=), a == b —— 檢測兩個變數的字面值是否相同
id(a)/id(b) —— 讀取單個變數對象的內存存儲地址
is(操作符) a is b —— 檢測兩個變數存儲的對象的內存存儲地址是否相同
舉例:
1、整形數值的字面值為於0-255之間
①值相同: X=1,Y=1時 —— 用 X == Y 檢測這些整形數值的字面值是相同的,都是1,用 id(X) 、 id(y)(調用X或 調用Y),檢測也都是指向同一地址11,這個值只佔用一個內存地址,並且值相同的情況下,不管有多少個變數來調用這個值,都會指向這個同一值和這個值得內存地址,地址設為11,此時X=Y=1,共同讀取內存地址11。
②值不同 :變化為X=1,Y=2 時 ——值不同(1、2)所以變數會分別指向不同值和不同內存地址,此時:X=1仍舊讀取地址11,Y=2讀取地址22。
③值相同:變化拓展為X=2,Y=2,Y=Z時——則X=Y=Z=2 讀取地址為22。
以上三種情況,X、Y、Z都是變數,1和2是值,11和22是內存地址。①和③里不同變數指向同一值並且內存地址也相同的機制稱為:內存地址的共享引用。但是這種不同變數引用相同值得到相同內存地址的情況僅限於整形數值的字面值在0-255之間,和部分短位元組中。這是因為0-255之間的值的地址已被Python預緩存在內存中,而當整形數值的字面值大於255時,即便不同變數引用相同字面值,但內存的分配的地址也絕對不可能相同。舉例如下
2、整形數值的字面值大於255
④值相同:X=500,Y=500時 —— 用 X == Y 檢測他們的字面值是相同的500 但是用id(X)、 id(y)或 X is Y檢測他們的內存地址時,雖然字面值相同,但字面值500大於255,所以X與Y不共享內存地址,此時X內存地址為55,Y地址為66
⑤值不同 :變化為X=500,Y=600 時 —— 字面值不同且500、600都大於255,所以變數會分別指向不同內存地址,此時:X值=500已在④中聲明過,所以X地址仍為55,Y因改變值則重新新建地址為77。
⑥值相同:再變化為x=600,y=600,y=z時——則x=y=z=600
用x == y ==z 檢測他們字面值相同都是600 ,但因字面值600大於255,所以x與y與z不共享內存地址。用id(x)、 id(y)、 id(z)檢測他們的內存地址也都不相同。此時:Y值=600已在⑤中聲明過,所以此地址不變Y地址仍為77,X因改變值則重新建地址為88、z新建內存地址99。(並且由於Python的垃圾回收機制,每一個釋放過的對象地址都可以被再次進行使用。所以⑥里X的地址也可以是之前④里Y已釋放的的地址66,⑥里Z也可以使用X之前的內存地址55或Y之前使用的66)變數不存儲值,而是綁定到值。當一個對象沒有被綁定到任何一個變數時,它會在合適的時候被銷毀,所佔用的內存空間也會被回收。所以當一個新的對象被創建時,完全有可能分配到曾經回收的內存。簡單可理解為對象地址是:先聲明先佔有,釋放則回收。
⑵ python的內存管理機制
論壇
活動
招聘
專題
打開CSDN APP
Copyright © 1999-2020, CSDN.NET, All Rights Reserved
登錄
XCCS_澍
關注
Python 的內存管理機制及調優手段? 原創
2018-08-05 06:50:53
XCCS_澍
碼齡7年
關注
內存管理機制:引用計數、垃圾回收、內存池。
一、引用計數:
引用計數是一種非常高效的內存管理手段, 當一個 Python 對象被引用時其引用計數增加 1, 當其不再被一個變數引用時則計數減 1. 當引用計數等於 0 時對象被刪除。
二、垃圾回收 :
1. 引用計數
引用計數也是一種垃圾收集機制,而且也是一種最直觀,最簡單的垃圾收集技術。當 Python 的某個對象的引用計數降為 0 時,說明沒有任何引用指向該對象,該對象就成為要被回收的垃圾了。比如某個新建對象,它被分配給某個引用,對象的引用計數變為 1。如果引用被刪除,對象的引用計數為 0,那麼該對象就可以被垃圾回收。不過如果出現循環引用的話,引用計數機制就不再起有效的作用了
2. 標記清除
如果兩個對象的引用計數都為 1,但是僅僅存在他們之間的循環引用,那麼這兩個對象都是需要被回收的,也就是說,它們的引用計數雖然表現為非 0,但實際上有效的引用計數為 0。所以先將循環引用摘掉,就會得出這兩個對象的有效計數。
3. 分代回收
從前面「標記-清除」這樣的垃圾收集機制來看,這種垃圾收集機制所帶來的額外操作實際上與系統中總的內存塊的數量是相關的,當需要回收的內存塊越多時,垃圾檢測帶來的額外操作就越多,而垃圾回收帶來的額外操作就越少;反之,當需回收的內存塊越少時,垃圾檢測就將比垃圾回收帶來更少的額外操作。
⑶ Python內存駐留機制
字元串駐留機制在許多面向對象編程語言中都支持,比如Java、python、Ruby、PHP等,它是一種數據緩存機制,對不可變數據類型使用同一個內存地址,有效的節省了空間,本文主要介紹Python的內存駐留機制。
字元串駐留就是每個字元串只有一個副本,多個對象共享該副本,駐留只針對不可變數據類型,比如字元串,布爾值,數字等。在這些固定數據類型處理中,使用駐留可以有效節省時間和空間,當然在駐留池中創建或者插入新的內容會消耗一定的時間。
下面舉例介紹python中的駐留機制。
在Python對象及內存管理機制一文中介紹了python的參數傳遞以及以及內存管理機制,來看下面一段代碼:
知道結果是什麼嗎?下面是執行結果:
l1和l2內容相同,卻指向了不同的內存地址,l2和l3之間使用等號賦值,所以指向了同一個對象。因為列表是可變對象,每創建一個列表,都會重新分配內存,列表對象是沒有「內存駐留」機制的。下面來看不可變數據類型的駐留機制。
在 Jupyter或者控制台交互環境 中執行下面代碼:
執行結果:
可以發現a1和b1指向了不同的地址,a2和b2指向了相同的地址,這是為什麼呢?
因為啟動時,Python 將一個 -5~256 之間整數列表預載入(緩存)到內存中,我們在這個范圍內創建一個整數對象時,python會自動引用緩存的對象,不會創建新的整數對象。
浮點型不支持:
如果上面的代碼在非交互環境,也就是將代碼作為python腳本運行的結果是什麼呢?(運行環境為python3.7)
全為True,沒有明確的限定臨界值,都進行了駐留操作。這是因為使用不同的環境時,代碼的優化方式不同。
在 Jupyter或者控制台交互環境 中:
滿足標識符命名規范的字元:
結果:
乘法獲取字元串(運行環境為python3.7)
結果:
在非交互環境中:
注意: 字元串是在編譯時進行駐留 ,也就是說,如果字元串的值不能在編譯時進行計算,將不會駐留。比如下面的例子:
在交互環境執行結果如下:
都指向不同的內存。
python 3.7 非交互環境執行結果:
發現d和e指向不同的內存,因為d和e不是在編譯時計算的,而是在運行時計算的。前面的 a = 'aa'*50 是在編譯時計算的。
除了上面介紹的python默認的駐留外,可以使用sys模塊中的intern()函數來指定駐留內容
結果:
使用intern()後,都指向了相同的地址。
本文主要介紹了python的內存駐留,內存駐留是python優化的一種策略,注意不同運行環境下優化策略不一樣,不同的python版本也不相同。注意字元串是在編譯時進行駐留。
--THE END--
⑷ python怎麼修改某個內存地址的數據
使用ctypes模塊調用WriteProcessMemory函數,在創建程序進程後,就可以修改該程序指定內存地址。WriteProcessMemory的函數原型如下所示。
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T* lpNumberOfBytesWritten
);
其參數含義如下。
· hProcess:要寫內存的進程句柄。
· lpBaseAddress:要寫的內存起始地址。
· lpBuffer:寫入值的地址。
· nSize:寫入值的大小。
· lpNumberOfBytesWritten :實際寫入的大小。
python代碼示例如下:
fromctypesimport*
#定義_PROCESS_INFORMATION結構體
class_PROCESS_INFORMATION(Structure):
_fields_=[('hProcess',c_void_p),
('hThread',c_void_p),
('dwProcessId',c_ulong),
('dwThreadId',c_ulong)]
#定義_STARTUPINFO結構體
class_STARTUPINFO(Structure):
_fields_=[('cb',c_ulong),
('lpReserved',c_char_p),
('lpDesktop',c_char_p),
('lpTitle',c_char_p),
('dwX',c_ulong),
('dwY',c_ulong),
('dwXSize',c_ulong),
('dwYSize',c_ulong),
('dwXCountChars',c_ulong),
('dwYCountChars',c_ulong),
('dwFillAttribute',c_ulong),
('dwFlags',c_ulong),
('wShowWindow',c_ushort),
('cbReserved2',c_ushort),
('lpReserved2',c_char_p),
('hStdInput',c_ulong),
('hStdOutput',c_ulong),
('hStdError',c_ulong)]
NORMAL_PRIORITY_CLASS=0x00000020#定義NORMAL_PRIORITY_CLASS
kernel32=windll.LoadLibrary("kernel32.dll")#載入kernel32.dll
CreateProcess=kernel32.CreateProcessA#獲得CreateProcess函數地址
ReadProcessMemory=kernel32.ReadProcessMemory#獲得ReadProcessMemory函數地址
WriteProcessMemory=kernel32.WriteProcessMemory#獲得WriteProcessMemory函數地址
TerminateProcess=kernel32.TerminateProcess
#聲明結構體
ProcessInfo=_PROCESS_INFORMATION()
StartupInfo=_STARTUPINFO()
file='ModifyMe.exe'#要進行修改的文件
address=0x0040103c#要修改的內存地址
buffer=c_char_p("_")#緩沖區地址
bytesRead=c_ulong(0)#讀入的位元組數
bufferSize=len(buffer.value)#緩沖區大小
#創建進程
ifCreateProcess(file,0,0,0,0,NORMAL_PRIORITY_CLASS,0,0,byref(StartupInfo),byref(ProcessInfo)):
#讀取要修改的內存地址,以判斷是否是要修改的文件
ifReadProcessMemory(ProcessInfo.hProcess,address,buffer,bufferSize,byref(bytesRead)):
ifbuffer.value=='x74':
buffer.value='x75'#修改緩沖區內的值,將其寫入內存
#修改內存
ifWriteProcessMemory(ProcessInfo.hProcess,address,buffer,bufferSize,byref(bytesRead)):
print'成功改寫內存!'
else:
print'寫內存錯誤!'
else:
print'打開了錯誤的文件!'
TerminateProcess(ProcessInfo.hProcess,0)#如果不是要修改的文件,則終止進程
else:
print'讀內存錯誤!'
else:
print'不能創建進程!'
⑸ python基於值的內存管理方式是什麼
Python採用基於值的內存管理模式。
在Python中一切皆對象,變數中存放的是對象的引用
python可以不用聲明變數類型而直接對變數進行賦值。對Python語言來講,對象的類型和內存都是在運行時確定的。這也是為什麼我們稱Python語言為動態類型的原因(這里我們把動態類型歸結為對變數內存地址的分配是在運行時自動判斷變數類型並對變數進行賦值)。
⑹ python變數與地址的關系
在C語言中,系統會為每個變數分配內存空間,當改變變數的值時,改變的是內存空間中的值,變數的地址是不改變的。
而在python中,Python採用的是基於值的管理方式。當給變數賦值時,系統會為這個值分配內存空間,然後讓這個變數指向這個值;當改變變數的值時,系統會為這個新的值分配另一個內存空間,然後還是讓這個變數指向這個新值。
這時,如果沒有任何變數指向內存空間的某個值,這個值稱為垃圾數據,系統會自動將其刪除,回收它佔用的內存空間。
例如:
x=12
x=3.1415926
變數x在指向3.1415926後,數值12就變成了垃圾數據。也可以使用del 命令 刪除變數,但是刪除之後就不能再使用了。否則會報錯:變數沒有定義。
也就是說,C語言中變數變的是內存空間中的值,不變的是地址;而在Python中,變數變的是地址,不變的是內存空間中的值。
python中查看變數地址可用:id(變數名)
⑺ python如何進行內存管理
Python的內存管理主要有三種機制:引用計數機制,垃圾回收機制和內存池機制。
引用計數機制
簡介
python內部使用引用計數,來保持追蹤內存中的對象,Python內部記錄了對象有多少個引用,即引用計數,當對象被創建時就創建了一個引用計數,當對象不再需要時,這個對象的引用計數為0時,它被垃圾回收。
特性
1.當給一個對象分配一個新名稱或者將一個對象放入一個容器(列表、元組或字典)時,該對象的引用計數都會增加。
2.當使用del對對象顯示銷毀或者引用超出作用於或者被重新賦值時,該對象的引用計數就會減少。
3.可以使用sys.getrefcount()函數來獲取對象的當前引用計數。多數情況下,引用計數要比我們猜測的大的多。對於不可變數據(數字和字元串),解釋器會在程序的不同部分共享內存,以便節約內存。
垃圾回收機制
特性
1.當內存中有不再使用的部分時,垃圾收集器就會把他們清理掉。它會去檢查那些引用計數為0的對象,然後清除其在內存的空間。當然除了引用計數為0的會被清除,還有一種情況也會被垃圾收集器清掉:當兩個對象相互引用時,他們本身其他的引用已經為0了。
2.垃圾回收機制還有一個循環垃圾回收器, 確保釋放循環引用對象(a引用b, b引用a, 導致其引用計數永遠不為0)。
內存池機制
簡介
在Python中,許多時候申請的內存都是小塊的內存,這些小塊內存在申請後,很快又會被釋放,由於這些內存的申請並不是為了創建對象,所以並沒有對象一級的內存池機制。這就意味著Python在運行期間會大量地執行malloc和free的操作,頻繁地在用戶態和核心態之間進行切換,這將嚴重影響Python的執行效率。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。
內存池概念
內存池的概念就是預先在內存中申請一定數量的,大小相等的內存塊留作備用,當有新的內存需求時,就先從內存池中分配內存給這個需求,不夠了之後再申請新的內存。這樣做最顯著的優勢就是能夠減少內存碎片,提升效率。內存池的實現方式有很多,性能和適用范圍也不一樣。
特性
1.Python提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。
2.Pymalloc機制。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。
3.Python中所有小於256個位元組的對象都使用pymalloc實現的分配器,而大的對象則使用系統的 malloc。
4.對於Python對象,如整數,浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。也就是說如果你分配又釋放了大量的整數,用於緩存這些整數的內存就不能再分配給浮點數。
⑻ Python如何進行內存管理
Python是如何進行內存管理的?
答:從三個方面來說,一對象的引用計數機制,二垃圾回收機制,三內存池機制。
一、對象的引用計數機制
Python內部使用引用計數,來保持追蹤內存中的對象,所有對象都有引用計數。
引用計數增加的情況:
1,一個對象分配一個新名稱
2,將其放入一個容器中(如列表、元組或字典)
引用計數減少的情況:
1,使用del語句對對象別名顯示的銷毀
2,引用超出作用域或被重新賦值
Sys.getrefcount( )函數可以獲得對象的當前引用計數
多數情況下,引用計數比你猜測得要大得多。對於不可變數據(如數字和字元串),解釋器會在程序的不同部分共享內存,以便節約內存。
相關推薦:《Python視頻教程》
二、垃圾回收
1,當一個對象的引用計數歸零時,它將被垃圾收集機制處理掉。
2,當兩個對象a和b相互引用時,del語句可以減少a和b的引用計數,並銷毀用於引用底層對象的名稱。然而由於每個對象都包含一個對其他對象的應用,因此引用計數不會歸零,對象也不會銷毀。(從而導致內存泄露)。為解決這一問題,解釋器會定期執行一個循環檢測器,搜索不可訪問對象的循環並刪除它們。
三、內存池機制
Python提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。
1,Pymalloc機制。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。
2,Python中所有小於256個位元組的對象都使用pymalloc實現的分配器,而大的對象則使用系統的malloc。
3,對於Python對象,如整數,浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。也就是說如果你分配又釋放了大量的整數,用於緩存這些整數的內存就不能再分配給浮點數。