導航:首頁 > 編程語言 > python銷毀變數釋放內存

python銷毀變數釋放內存

發布時間:2022-05-09 10:06:09

A. 如何手動釋放python的內存

象的引用計數減少;

函數運行結束,所有局部變數都被銷毀,對象的引用計數也就隨之減少。例如 foo(x) 運行結束,x 被銷毀;
當變數被賦值給另一個對象時,原對象的引用計數也會減少。例如 x = 4,這時候 3 這個對象的引用計數就減 1 了;

使用 del 刪除一個變數也會導致對象引用減少。例如 del x;

對象從集合對象中移除。例如 lst.remove(x);

包含對象的集合對象被銷毀。例如 del lst;
這些操作都可能使對象變成垃圾回收對象,由垃圾收集器負責收集,當然垃圾收集器也負責處理循環引用對象。
要立即釋放,可以使用下面的代碼
import gc
gc.collect()

B. python中變數用完怎麼清除

python內存自動回收,一般而言,不需要顯示的來釋和內存。如果你實在想的話就del 變數名就行了
>>> a=1
>>> a
1
>>> del a

C. 如何讓python的GC機制崩潰

(Memory Leak,內存泄漏)
為什麼會產生內存泄漏?
當一個對象已經不需要再使用本該被回收時,另外一個正在使用的對象持有它的引用從而導致它不能被回收,這導致本該被回收的對象不能被回收而停留在堆內存中,這就產生了內存泄漏。
內存泄漏對程序的影響?
內存泄漏是造成應用程序OOM的主要原因之一。我們知道Android系統為每個應用程序分配的內存是有限的,而當一個應用中產生的內存泄漏比較多時,這就難免會導致應用所需要的內存超過系統分配的內存限額,這就造成了內存溢出從而導致應用Crash。
如何檢查和分析內存泄漏?
因為內存泄漏是在堆內存中,所以對我們來說並不是可見的。通常我們可以藉助MAT、LeakCanary等工具來檢測應用程序是否存在內存泄漏。
1、MAT是一款強大的內存分析工具,功能繁多而復雜。
2、LeakCanary則是由Square開源的一款輕量級的第三方內存泄漏檢測工具,當檢測到程序中產生內存泄漏時,它將以最直觀的方式告訴我們哪裡產生了內存泄漏和導致誰泄漏了而不能被回收。
常見的內存泄漏及解決方法
1、單例造成的內存泄漏
由於單例的靜態特性使得其生命周期和應用的生命周期一樣長,如果一個對象已經不再需要使用了,而單例對象還持有該對象的引用,就會使得該對象不能被正常回收,從而導致了內存泄漏。
示例:防止單例導致內存泄漏的實例
// 使用了單例模式
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static AppManager getInstance(Context context) {
if (instance != null) {
instance = new AppManager(context);
}
return instance;
}
}

這樣不管傳入什麼Context最終將使用Application的Context,而單例的生命周期和應用的一樣長,這樣就防止了內存泄漏。???
2、非靜態內部類創建靜態實例造成的內存泄漏
例如,有時候我們可能會在啟動頻繁的Activity中,為了避免重復創建相同的數據資源,可能會出現如下寫法:
public class MainActivity extends AppCompatActivity {

private static TestResource mResource = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(mResource == null){
mResource = new TestResource();
}
//...
}

class TestResource {
//...
}
}

這樣在Activity內部創建了一個非靜態內部類的單例,每次啟動Activity時都會使用該單例的數據。雖然這樣避免了資源的重復創建,但是這種寫法卻會造成內存泄漏。因為非靜態內部類默認會持有外部類的引用,而該非靜態內部類又創建了一個靜態的實例,該實例的生命周期和應用的一樣長,這就導致了該靜態實例一直會持有該Activity的引用,從而導致Activity的內存資源不能被正常回收。
解決方法:將該內部類設為靜態內部類或將該內部類抽取出來封裝成一個單例,如果需要使用Context,就使用Application的Context。
3、Handler造成的內存泄漏
示例:創建匿名內部類的靜態對象
public class MainActivity extends AppCompatActivity {

private final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

new Thread(new Runnable() {
@Override
public void run() {
// ...
handler.sendEmptyMessage(0x123);
}
});
}
}

1、從Android的角度
當Android應用程序啟動時,該應用程序的主線程會自動創建一個Looper對象和與之關聯的MessageQueue。當主線程中實例化一個Handler對象後,它就會自動與主線程Looper的MessageQueue關聯起來。所有發送到MessageQueue的Messag都會持有Handler的引用,所以Looper會據此回調Handle的handleMessage()方法來處理消息。只要MessageQueue中有未處理的Message,Looper就會不斷的從中取出並交給Handler處理。另外,主線程的Looper對象會伴隨該應用程序的整個生命周期。
2、 java角度
在Java中,非靜態內部類和匿名類內部類都會潛在持有它們所屬的外部類的引用,但是靜態內部類卻不會。
對上述的示例進行分析,當MainActivity結束時,未處理的消息持有handler的引用,而handler又持有它所屬的外部類也就是MainActivity的引用。這條引用關系會一直保持直到消息得到處理,這樣阻止了MainActivity被垃圾回收器回收,從而造成了內存泄漏。
解決方法:將Handler類獨立出來或者使用靜態內部類,這樣便可以避免內存泄漏。
4、線程造成的內存泄漏
示例:AsyncTask和Runnable
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

new Thread(new MyRunnable()).start();
new MyAsyncTask(this).execute();
}

class MyAsyncTask extends AsyncTask<Void, Void, Void> {

// ...

public MyAsyncTask(Context context) {
// ...
}

@Override
protected Void doInBackground(Void... params) {
// ...
return null;
}

@Override
protected void onPostExecute(Void aVoid) {
// ...
}
}

class MyRunnable implements Runnable {
@Override
public void run() {
// ...
}
}
}

AsyncTask和Runnable都使用了匿名內部類,那麼它們將持有其所在Activity的隱式引用。如果任務在Activity銷毀之前還未完成,那麼將導致Activity的內存資源無法被回收,從而造成內存泄漏。
解決方法:將AsyncTask和Runnable類獨立出來或者使用靜態內部類,這樣便可以避免內存泄漏。
5、資源未關閉造成的內存泄漏
對於使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源,應該在Activity銷毀時及時關閉或者注銷,否則這些資源將不會被回收,從而造成內存泄漏。
1)比如在Activity中register了一個BraodcastReceiver,但在Activity結束後沒有unregister該BraodcastReceiver。
2)資源性對象比如Cursor,Stream、File文件等往往都用了一些緩沖,我們在不使用的時候,應該及時關閉它們,以便它們的緩沖及時回收內存。它們的緩沖不僅存在於 java虛擬機內,還存在於java虛擬機外。如果我們僅僅是把它的引用設置為null,而不關閉它們,往往會造成內存泄漏。
3)對於資源性對象在不使用的時候,應該調用它的close()函數將其關閉掉,然後再設置為null。在我們的程序退出時一定要確保我們的資源性對象已經關閉。
4)Bitmap對象不在使用時調用recycle()釋放內存。2.3以後的bitmap應該是不需要手動recycle了,內存已經在java層了。
6、使用ListView時造成的內存泄漏
初始時ListView會從BaseAdapter中根據當前的屏幕布局實例化一定數量的View對象,同時ListView會將這些View對象緩存起來。當向上滾動ListView時,原先位於最上面的Item的View對象會被回收,然後被用來構造新出現在下面的Item。這個構造過程就是由getView()方法完成的,getView()的第二個形參convertView就是被緩存起來的Item的View對象(初始化時緩存中沒有View對象則convertView是null)。
構造Adapter時,沒有使用緩存的convertView。
解決方法:在構造Adapter時,使用緩存的convertView。
7、集合容器中的內存泄露
我們通常把一些對象的引用加入到了集合容器(比如ArrayList)中,當我們不需要該對象時,並沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。
解決方法:在退出程序之前,將集合里的東西clear,然後置為null,再退出程序。
8、WebView造成的泄露
當我們不要使用WebView對象時,應該調用它的destory()函數來銷毀它,並釋放其佔用的內存,否則其長期佔用的內存也不能被回收,從而造成內存泄露。
解決方法:為WebView另外開啟一個進程,通過AIDL與主線程進行通信,WebView所在的進程可以根據業務的需要選擇合適的時機進行銷毀,從而達到內存的完整釋放。
如何避免內存泄漏?
1、在涉及使用Context時,對於生命周期比Activity長的對象應該使用Application的Context。凡是使用Context優先考慮Application的Context,當然它並不是萬能的,對於有些地方則必須使用Activity的Context。對於Application,Service,Activity三者的Context的應用場景如下:

其中,NO1表示Application和Service可以啟動一個Activity,不過需要創建一個新的task任務隊列。而對於Dialog而言,只有在Activity中才能創建。除此之外三者都可以使用。
2、對於需要在靜態內部類中使用非靜態外部成員變數(如:Context、View ),可以在靜態內部類中使用弱引用來引用外部類的變數來避免內存泄漏。
3、對於不再需要使用的對象,顯示的將其賦值為null,比如使用完Bitmap後先調用recycle(),再賦為null。
4、保持對對象生命周期的敏感,特別注意單例、靜態對象、全局性集合等的生命周期。
5、對於生命周期比Activity長的內部類對象,並且內部類中使用了外部類的成員變數,可以這樣做避免內存泄漏:
1)將內部類改為靜態內部類
2)靜態內部類中使用弱引用來引用外部類的成員變數

D. python如何清理內存

引用計數,這是 Python 的垃圾回收策略。補充一下。

解釋器(也就是你說的 Shell)負責跟蹤對象的引用計數,垃圾收集器負責釋放內存。

如何釋放?可以通過銷毀對象的引用,使引用計數減少至 0。假設 x = 3,以下情況會使 3 這個整型對象的引用計數減少;

函數運行結束,所有局部變數都被銷毀,對象的引用計數也就隨之減少。例如 foo(x) 運行結束,x 被銷毀;當變數被賦值給另一個對象
時,原對象的引用計數也會減少。例如 x = 4,這時候 3 這個對象的引用計數就減 1 了;

使用 del 刪除一個變數也會導致對象引用減少。例如 del x;

對象從集合對象中移除。例如 lst.remove(x);

包含對象的集合對象被銷毀。例如 del lst;

這些操作都可能使對象變成垃圾回收對象,由垃圾收集器負責收集,當然垃圾收集器也負責處理循環引用對象。
推薦學習《python教程》。

E. Python問題 想問下刪除一個類的時候有必要用del 類名來刪除嗎,我覺得直接將代碼刪掉不就可以了嗎

首先你要明白,你說的刪除,是從哪裡刪除?
del在python程序運行的時候,從內存中「刪除」變數,其本質是將變數佔用的內存空間釋放掉。
而你說的將代碼刪掉,則是在python程序編碼階段進行的操作,如果代碼被刪掉,那就不可能被程序載入到內存中。

F. python 變數被賦值後原來的內存被回收嗎


問題解決,只要沒有循環套用返回值本身,將其賦值給新變數,然後del原變數,gc.collect()之後,內存即可回收

G. python如何讓程序一直運行且內存資源自動釋放

這當然是和代碼寫法有關,不貼出來就無法解決

H. python 什麼時候 垃圾回收

Python中的垃圾回收是以引用計數為主,分代收集為輔。引用計數的缺陷是循環引用的問題。
在Python中,如果一個對象的引用數為0,Python虛擬機就會回收這個對象的內存。
#encoding=utf-8
__author__ = '[email protected]'

class ClassA():
def __init__(self):
print 'object born,id:%s'%str(hex(id(self)))
def __del__(self):
print 'object del,id:%s'%str(hex(id(self)))

def f1():
while True:
c1=ClassA()
del c1

執行f1()會循環輸出這樣的結果,而且進程佔用的內存基本不會變動
object born,id:0x237cf58
object del,id:0x237cf58

c1=ClassA()會創建一個對象,放在0x237cf58內存中,c1變數指向這個內存,這時候這個內存的引用計數是1
del c1後,c1變數不再指向0x237cf58內存,所以這塊內存的引用計數減一,等於0,所以就銷毀了這個對象,然後釋放內存。
1、導致引用計數+1的情況

對象被創建,例如a=23
對象被引用,例如b=a
對象被作為參數,傳入到一個函數中,例如func(a)
對象作為一個元素,存儲在容器中,例如list1=[a,a]

2、導致引用計數-1的情況

對象的別名被顯式銷毀,例如del a
對象的別名被賦予新的對象,例如a=24
一個對象離開它的作用域,例如f函數執行完畢時,func函數中的局部變數(全局變數不會)
對象所在的容器被銷毀,或從容器中刪除對象

demo
def func(c,d):
print 'in func function', sys.getrefcount(c) - 1

print 'init', sys.getrefcount(11) - 1
a = 11
print 'after a=11', sys.getrefcount(11) - 1
b = a
print 'after b=1', sys.getrefcount(11) - 1
func(11)
print 'after func(a)', sys.getrefcount(11) - 1
list1 = [a, 12, 14]
print 'after list1=[a,12,14]', sys.getrefcount(11) - 1
a=12
print 'after a=12', sys.getrefcount(11) - 1
del a
print 'after del a', sys.getrefcount(11) - 1
del b
print 'after del b', sys.getrefcount(11) - 1
# list1.pop(0)
# print 'after pop list1',sys.getrefcount(11)-1
del list1
print 'after del list1', sys.getrefcount(11) - 1

輸出
init 24
after a=11 25
after b=1 26
in func function 28
after func(a) 26
after list1=[a,12,14] 27
after a=12 26
after del a 26
after del b 25
after del list1 24

問題:為什麼調用函數會令引用計數+2
3、查看一個對象的引用計數
sys.getrefcount(a)可以查看a對象的引用計數,但是比正常計數大1,因為調用函數的時候傳入a,這會讓a的引用計數+1
二.循環引用導致內存泄露

def f2():
while True:
c1=ClassA()
c2=ClassA()
c1.t=c2
c2.t=c1
del c1
del c2

執行f2(),進程佔用的內存會不斷增大。
object born,id:0x237cf30
object born,id:0x237cf58

創建了c1,c2後,0x237cf30(c1對應的內存,記為內存1),0x237cf58(c2對應的內存,記為內存2)這兩塊內存的引用計數都是1,執行c1.t=c2和c2.t=c1後,這兩塊內存的引用計數變成2.
在del c1後,內存1的對象的引用計數變為1,由於不是為0,所以內存1的對象不會被銷毀,所以內存2的對象的引用數依然是2,在del c2後,同理,內存1的對象,內存2的對象的引用數都是1。
雖然它們兩個的對象都是可以被銷毀的,但是由於循環引用,導致垃圾回收器都不會回收它們,所以就會導致內存泄露。
三.垃圾回收

deff3():
# print gc.collect()
c1=ClassA()
c2=ClassA()
c1.t=c2
c2.t=c1
del c1
del c2
print gc.garbage
print gc.collect() #顯式執行垃圾回收
print gc.garbage
time.sleep(10)
if __name__ == '__main__':
gc.set_debug(gc.DEBUG_LEAK) #設置gc模塊的日誌
f3()

輸出:
gc: uncollectable <ClassA instance at 0230E918>
gc: uncollectable <ClassA instance at 0230E940>
gc: uncollectable <dict 0230B810>
gc: uncollectable <dict 02301ED0>
object born,id:0x230e918
object born,id:0x230e940
4

垃圾回收後的對象會放在gc.garbage列表裡面
gc.collect()會返回不可達的對象數目,4等於兩個對象以及它們對應的dict
有三種情況會觸發垃圾回收:

1.調用gc.collect(),
2.當gc模塊的計數器達到閥值的時候。
3.程序退出的時候
四.gc模塊常用功能解析
gc模塊提供一個介面給開發者設置垃圾回收的選項。上面說到,採用引用計數的方法管理內存的一個缺陷是循環引用,而gc模塊的一個主要功能就是解決循環引用的問題。
常用函數:
1、gc.set_debug(flags)
設置gc的debug日誌,一般設置為gc.DEBUG_LEAK
2、gc.collect([generation])
顯式進行垃圾回收,可以輸入參數,0代表只檢查第一代的對象,1代表檢查一,二代的對象,2代表檢查一,二,三代的對象,如果不傳參數,執行一個full collection,也就是等於傳2。
返回不可達(unreachable objects)對象的數目
3、gc.set_threshold(threshold0[, threshold1[, threshold2])
設置自動執行垃圾回收的頻率。
4、gc.get_count()
獲取當前自動執行垃圾回收的計數器,返回一個長度為3的列表
5、gc模塊的自動垃圾回收機制
必須要import gc模塊,並且is_enable()=True才會啟動自動垃圾回收。
這個機制的主要作用就是發現並處理不可達的垃圾對象。
垃圾回收=垃圾檢查+垃圾回收
在Python中,採用分代收集的方法。把對象分為三代,一開始,對象在創建的時候,放在一代中,如果在一次一代的垃圾檢查中,改對象存活下來,就會被放到二代中,同理在一次二代的垃圾檢查中,該對象存活下來,就會被放到三代中。
gc模塊裡面會有一個長度為3的列表的計數器,可以通過gc.get_count()獲取。
例如(488,3,0),其中488是指距離上一次一代垃圾檢查,Python分配內存的數目減去釋放內存的數目,注意是內存分配,而不是引用計數的增加。例如:
print gc.get_count() # (590, 8, 0)
a = ClassA()
print gc.get_count() # (591, 8, 0)
del a
print gc.get_count() # (590, 8, 0)

3是指距離上一次二代垃圾檢查,一代垃圾檢查的次數,同理,0是指距離上一次三代垃圾檢查,二代垃圾檢查的次數。
gc模快有一個自動垃圾回收的閥值,即通過gc.get_threshold函數獲取到的長度為3的元組,例如(700,10,10)
每一次計數器的增加,gc模塊就會檢查增加後的計數是否達到閥值的數目,如果是,就會執行對應的代數的垃圾檢查,然後重置計數器
例如,假設閥值是(700,10,10):
當計數器從(699,3,0)增加到(700,3,0),gc模塊就會執行gc.collect(0),即檢查一代對象的垃圾,並重置計數器為(0,4,0)
當計數器從(699,9,0)增加到(700,9,0),gc模塊就會執行gc.collect(1),即檢查一、二代對象的垃圾,並重置計數器為(0,0,1)
當計數器從(699,9,9)增加到(700,9,9),gc模塊就會執行gc.collect(2),即檢查一、二、三代對象的垃圾,並重置計數器為(0,0,0)

I. Python如何管理內存

Python中的內存管理是從三個方面來進行的,一對象的引用計數機制,二垃圾回收機制,三內存池機制
一、對象的引用計數機制
Python內部使用引用計數,來保持追蹤內存中的對象,所有對象都有引用計數。
引用計數增加的情況:
1,一個對象分配一個新名稱
2,將其放入一個容器中(如列表、元組或字典)
引用計數減少的情況:
1,使用del語句對對象別名顯示的銷毀
2,引用超出作用域或被重新賦值
sys.getrefcount( )函數可以獲得對象的當前引用計數
多數情況下,引用計數比你猜測得要大得多。對於不可變數據(如數字和字元串),解釋器會在程序的不同部分共享內存,以便節約內存。
二、垃圾回收
1,當一個對象的引用計數歸零時,它將被垃圾收集機制處理掉。
2,當兩個對象a和b相互引用時,del語句可以減少a和b的引用計數,並銷毀用於引用底層對象的名稱。然而由於每個對象都包含一個對其他對象的應用,因此引用計數不會歸零,對象也不會銷毀。(從而導致內存泄露)。為解決這一問題,解釋器會定期執行一個循環檢測器,搜索不可訪問對象的循環並刪除它們。
三、內存池機制
Python提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。
1,Pymalloc機制。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。
2,Python中所有小於256個位元組的對象都使用pymalloc實現的分配器,而大的對象則使用系統的malloc。
3,對於Python對象,如整數,浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。也就是說如果你分配又釋放了大量的整數,用於緩存這些整數的內存就不能再分配給浮點數。

閱讀全文

與python銷毀變數釋放內存相關的資料

熱點內容
cad最下面的一排命令都什麼意思 瀏覽:456
pythonimportcpp 瀏覽:850
W10的系統怎麼給U盤加密 瀏覽:370
華為手機代碼編程教學入門 瀏覽:762
和彩雲沒會員怎樣解壓 瀏覽:634
androidimageview保存 瀏覽:387
新買店鋪什麼伺服器 瀏覽:883
文件夾能直接刻錄嗎 瀏覽:493
androidxmpp刪除好友 瀏覽:969
javac哪個前景好 瀏覽:427
中華英才網app為什麼不能搜索了 瀏覽:660
伺服器域名是什麼意思 瀏覽:52
Linux導出mysql命令 瀏覽:159
無詐建鄴是什麼app 瀏覽:228
python中的雙色球 瀏覽:166
python解釋器里如何換行 瀏覽:411
python編寫格式 瀏覽:575
用python做出來的軟體 瀏覽:469
伺服器指示燈代表什麼 瀏覽:702
做一個單片機銷售需要知識 瀏覽:777