python 內(nèi)存管理,內(nèi)存泄漏

內(nèi)存管理機(jī)制

Python的內(nèi)存管理內(nèi)存總共分為4層(Layer0-3):

第一層Layer1的僅僅是對malloc的簡單包裝,raw memory踩娘,目的是為了兼容各個(gè)操作系統(tǒng),因?yàn)椴煌牟僮飨到y(tǒng)調(diào)用malloc的時(shí)候可能會有不同的行為結(jié)果喉祭;第二層Layer2是內(nèi)存管理機(jī)制的核心养渴,其中g(shù)c就是在這一層發(fā)揮至關(guān)重要的作用。第三層泛烙,是對象緩沖池理卑,如python對一些對象的直接操作,包括int蔽氨,list等藐唠。
對于可能被經(jīng)常使用、而且是immutable的對象鹉究,如bool類型宇立,元祖類型,小的整數(shù)自赔、長度較短的字符串等妈嘹,python會緩存在layer3,直接供python調(diào)用匿级,避免頻繁創(chuàng)建和銷毀蟋滴。

>>> a,b=1234567890123,1234567890123
>>> a is b
True
>>> a,b=(1,2,3,'a'),(1,2,3,'a')
>>> a is b
False
>>> a,b=('a'),('a')
>>> a is b
True

當(dāng)一個(gè)對象邏輯上不被使用了染厅,但并沒有被釋放痘绎,那么就存在內(nèi)存泄露,很有可能會造成程序效率低下甚至崩潰肖粮;
Python分配內(nèi)存的時(shí)候又分為大內(nèi)存和小內(nèi)存孤页。大小以256字節(jié)為界限,對于大內(nèi)存使用Malloc進(jìn)行分配涩馆,而對于小內(nèi)存則使用內(nèi)存池進(jìn)行分配行施。由于小內(nèi)存的分配和釋放是頻繁的允坚,因此內(nèi)存池的使用大大提高了python的執(zhí)行效率。

引用計(jì)數(shù)

在python中大多數(shù)對象的生命周期都是通過引用計(jì)數(shù)來管理的蛾号,引用計(jì)數(shù)也是一種最直觀最簡單的垃圾收集技術(shù)
每個(gè)python對象都有一個(gè)引用計(jì)數(shù)器稠项,用于記錄多少變量指向這個(gè)對象,可以通過sys模塊的getrefcount查詢獲得鲜结。

>>> sys.getrefcount({'a':1})
1
>>> sys.getrefcount(1)
590

每一個(gè)對象都會維護(hù)一個(gè)引用計(jì)數(shù)器展运,當(dāng)一個(gè)對象被引用的時(shí)候,它的計(jì)數(shù)器就+1精刷,當(dāng)一個(gè)對象的引用被銷毀時(shí)拗胜,計(jì)數(shù)器-1,當(dāng)這個(gè)對象的引用計(jì)數(shù)為0的時(shí)候怒允,說明這個(gè)對象已經(jīng)沒有使用了埂软,可以被釋放,就會被回收纫事,具有實(shí)時(shí)性勘畔。由于引用計(jì)數(shù)需要維護(hù)計(jì)數(shù)器等額外的操作,為了與引用計(jì)數(shù)搭配儿礼,在內(nèi)存的分配和釋放上獲得最高的效率咖杂,python因此設(shè)計(jì)了大量的內(nèi)存池機(jī)制。
下面這些情況引用計(jì)數(shù)+1:

  1. 對象被創(chuàng)建:a=4
  2. 引用被復(fù)制:y=x
  3. 被作為參數(shù)傳遞給函數(shù):f(x)
  4. 作為容器對象的一個(gè)元素:a=[1,x]

下面這些情況引用計(jì)數(shù)-1

  1. 離開作用域蚊夫。比如f(x)函數(shù)結(jié)束時(shí)诉字,x指向的對象引用減1。
  2. 引用被顯式的銷毀:del x
  3. 對象的一個(gè)別名被賦值給其他對象:y=1
  4. 對象從一個(gè)容器對象中移除:l.remove(x)
  5. 容器對象本身被銷毀:del l知纷。

python 的內(nèi)存管理主要以引用計(jì)數(shù)為主壤圃,引用計(jì)數(shù)機(jī)制能釋放大部分無用對象,除了一種情況琅轧,循環(huán)引用伍绳,因?yàn)檠h(huán)引用的對象引用計(jì)數(shù)器永不為0.
循環(huán)引用,就是一個(gè)對象直接或者間接引用自己本身,導(dǎo)致計(jì)數(shù)器不為0:

class Test(object):
    pass
t1 = Test()
t1.a = t1

a, b = Test(), Test()
a.attr_b = b
b.attr_a = a
l1=[]
l2=[]
l1.append(l2)
l2.append(l1)

標(biāo)記清除

標(biāo)記清除算法作為Python的輔助垃圾收集技術(shù)主要處理的是一些容器對象乍桂,比如list冲杀、dict、tuple睹酌,instance等权谁,因?yàn)閷τ谧址?shù)值對象是不可能造成循環(huán)引用問題憋沿。標(biāo)記清除和分代回收就是為了解決循環(huán)引用而生的旺芽。
標(biāo)記清除會使用垃圾收集監(jiān)控對象,講對象放到鏈表上,被垃圾收集監(jiān)控的對象并非只有垃圾收集機(jī)制才能回收采章,正常的引用計(jì)數(shù)就能銷毀一個(gè)被納入垃圾收集機(jī)制監(jiān)控的對象运嗜。雖然有很多對象掛在垃圾收集機(jī)制監(jiān)控的鏈表上,但實(shí)際更多時(shí)候悯舟,是引用計(jì)數(shù)機(jī)制在維護(hù)這些對象担租,只有對引用計(jì)數(shù)無能為力的循環(huán)引用,垃圾收集機(jī)制才起作用抵怎,事實(shí)上翩活,除循環(huán)引用外的對象,垃圾收集機(jī)制是無能為力的便贵,因?yàn)閽煸诶占瘷C(jī)制上的對象都是引用計(jì)數(shù)不為0的菠镇,如果是0,早就被引用計(jì)數(shù)清理了承璃。

del x 并不一定會調(diào)用__del__方法利耍,只有引用計(jì)數(shù) == 0時(shí),__del__()才會被執(zhí)行盔粹,如果一個(gè)Python對象定義了__del__這個(gè)方法, Python的垃圾回收機(jī)制即使發(fā)現(xiàn)該對象不可到達(dá) 也不會釋放他. 原因是__del__這個(gè)方式是當(dāng)一個(gè)Python對象引用計(jì)數(shù)為0即將被刪除前調(diào)用用來做清理工作的.由于垃圾回收找到的需要釋放的對象中往往存在循環(huán)引用的情況, 對于循環(huán)引用的對象a和b, 應(yīng)該先調(diào)用哪 一個(gè)對象的__del__是無法決定的,當(dāng)執(zhí)行垃圾回收的時(shí)候隘梨,會將循環(huán)引用中定義了__del__函數(shù)的類實(shí)例放到gc.garbage列表, 因此Python垃圾回收機(jī)制就放棄釋放這些對象,會造成事實(shí)上的內(nèi)存泄露, 轉(zhuǎn)而將這些對象保存起來, 應(yīng)避免在代碼中定義__del__方法.

import time
class Test(object):
    def __init__(self, name):
        self.__name = name

    def __del__(self):
        print("__del__方法被調(diào)用")
# 創(chuàng)建對象
cat = Test("貓")
cat2 = cat
del cat
del cat2
time.sleep(10)

垃圾回收時(shí)舷嗡,Python不能進(jìn)行其它的任務(wù)轴猎,會造成程序卡頓。頻繁的垃圾回收將大大降低Python的工作效率进萄。當(dāng)Python運(yùn)行時(shí)捻脖,會記錄其中分配對象和取消分配對象的次數(shù)。當(dāng)兩者的差值高于某個(gè)閾值時(shí)中鼠,垃圾回收才會啟動(dòng)可婶。

>>> import gc
>>> print(gc.get_threshold())
(700, 10, 10)
>>> 

700是垃圾回收啟動(dòng)的閾值,后面兩個(gè)10和分代回收有關(guān)援雇,也就是新增對象與釋放對象的差值為700時(shí)矛渴,進(jìn)行一次垃圾回收,主要目標(biāo)是循環(huán)引用惫搏,這個(gè)時(shí)候會造成卡頓

gc.enable(); gc.disable(); gc.isenabled() #開啟gc(默認(rèn))具温;關(guān)閉gc;判斷gc是否開啟
gc.collection() #執(zhí)行一次垃圾回收筐赔,不管gc是否處于開啟狀態(tài)都能使用
gc.set_threshold(t0, t1, t2)  #設(shè)置垃圾回收閾值铣猩; 
gc.get_threshold() # 獲得當(dāng)前的垃圾回收閾值
gc.get_objects() #獲取所有被垃圾回收器監(jiān)控管理的對象
gc.get_referents(obj) #返回obj對象直接指向的對象
gc.get_referrers(obj) #返回所有直接指向obj的對象

分代回收

同時(shí),分代回收是建立在標(biāo)記清除技術(shù)基礎(chǔ)之上川陆。分代回收同樣作為Python的輔助垃圾收集技術(shù)處理那些容器對象
Python將所有的對象分為0剂习,1,2三代较沪。所有的新建對象都是0代對象鳞绕。當(dāng)某一代對象經(jīng)歷過垃圾回收,依然存活尸曼,那么它就被歸入下一代對象们何。get_threshold()返回的(700, 10, 10)返回的兩個(gè)10。也就是說控轿,每10次0代垃圾回收冤竹,會配合1次1代的垃圾回收;而每10次1代的垃圾回收茬射,才會有1次的2代垃圾回收鹦蠕。理論上,存活時(shí)間久的對象在抛,使用的越多钟病,越不容易被回收,這也是分代回收設(shè)計(jì)的思想刚梭。

內(nèi)存泄漏

本文是在python2環(huán)境下

發(fā)生內(nèi)存泄漏的兩中情況:
第一是對象被另一個(gè)生命周期特別長的對象所引用
第二是循環(huán)引用中的對象定義了_del_函數(shù)

檢測內(nèi)存泄漏的工具有很多肠阱,這里列舉幾種常見且有用的工具:

  • objgraph python2,3下都可使用
  • tracemalloc python3下使用
  • pympler

objgraph

文檔地址:https://mg.pov.lt/objgraph/

# dot t.dot -T png -o pic.png
count(typename) #返回該類型對象的數(shù)目朴读,其實(shí)就是通過gc.get_objects()拿到所用的對象屹徘,然后統(tǒng)計(jì)指定類型的數(shù)目。
by_type(typename) #返回該類型的對象列表衅金。線上項(xiàng)目噪伊,可以用這個(gè)函數(shù)很方便找到一個(gè)單例對象
show_most_common_types(limits = 10)# 打印實(shí)例最多的前N(limits)個(gè)對象,調(diào)用前,最好先gc.collet一下
show_backrefs() #生成有關(guān)objs的引用圖氮唯,看出看出對象為什么不釋放酥宴。
find_backref_chain(obj, predicate, max_depth=20, extra_ignore=()) #找到一條指向obj對象的最短路徑,且路徑的頭部節(jié)點(diǎn)需要滿足predicate函數(shù) (返回值為True)可以快捷您觉、清晰指出 對象的被引用的情況拙寡,后面會展示這個(gè)函數(shù)的威力
show_chain() # 將find_backref_chain 找到的路徑畫出來。
show_growth 可以看出自上次調(diào)用后琳水,對象的增長情況
# -*- coding:utf-8 -*-
import time,gc,objgraph

class Test(object):
    def __init__(self, name):
        self.__name = name

    def __del__(self):
        print("__del__ is called!")
# 創(chuàng)建對象

class L(list):
    def __del__(self):
        print('list')

def leak():
    objgraph.show_growth()
    a = Test("a")
    b = Test("b")
    # c=a
    a.attrb = b
    b.attra = a

    l1 = L([1,2])
    l2 = L([3,4])
    l1.append(l2)
    l2.append(l1)

    
leak()
# gc.collect()
print('----------')
objgraph.show_growth()

當(dāng)定位到哪個(gè)對象存在內(nèi)存泄漏肆糕,就可以用show_backrefs查看這個(gè)對象的引用鏈。

# -*- coding:utf-8 -*-
import time,gc,objgraph

class Test(object):
    def __init__(self, name):
        self.__name = name

    def __del__(self):
        print("__del__ is called!")
# 創(chuàng)建對象

class L(list):
    def __del__(self):
        print('list')

def leak():
    # objgraph.show_growth()
    a = Test("a")
    b = Test("b")
    # c=a
    a.attrb = b
    b.attra = a

    del a,b

    l1 = L([1,2])
    l2 = L([3,4])
    l1.append(l2)
    l2.append(l1)

    
leak()
gc.collect()
print(gc.garbage)
print('----------')
# objgraph.show_growth()
objgraph.show_backrefs(objgraph.by_type('Test')[0], max_depth = 10, filename = 'pic.png')
# objgraph.show_backrefs(objgraph.by_type('Test')[0], extra_ignore=(id(gc.garbage),),  max_depth = 10, filename = 'pic.png')

上圖所示在孝,Test類的對象存在循環(huán)引用诚啃,并且無法用gc清除,因?yàn)檠h(huán)引用對象定義了_del_方法私沮。另外始赎,可以看見gc.garbage(類型是list)也引用了這兩個(gè)對象,原因在于當(dāng)執(zhí)行垃圾回收的時(shí)候,會將定義了del函數(shù)的類實(shí)例(被稱為uncollectable object)放到gc.garbage列表造垛,因此魔招,也可以直接通過查看gc.garbage來找出定義了del的循環(huán)引用。在這里五辽,通過增加extra_ignore來排除gc.garbage的影響办斑。代碼越復(fù)雜,相互之間的引用關(guān)系越多杆逗,show_backrefs越難以看懂乡翅。這個(gè)時(shí)候就可以使用show_chain和find_backref_chain

# -*- coding:utf-8 -*-
import time,gc,objgraph

class Test(object):
    def __init__(self, name):
        self.__name = name

    def __del__(self):
        print("__del__ is called!")
# 創(chuàng)建對象

class L(list):
    def __del__(self):
        print('list')

def leak():
    # objgraph.show_growth()
    a = Test("a")
    b = Test("b")
    # c=a
    a.attrb = b
    b.attra = a

    l1 = L([1,2])
    l2 = L([3,4])
    l1.append(l2)
    l2.append(l1)

    
leak()
# gc.collect()
print('----------')
# objgraph.show_growth()
# objgraph.show_backrefs(objgraph.by_type('Test')[0], max_depth = 10, filename = 'chain.png')
objgraph.show_chain(
    objgraph.find_backref_chain(
        objgraph.by_type('Test')[0],
        objgraph.is_proper_module
    ),
    filename='chain.png'
)

對象定義了_del_方法,且存在循環(huán)引用罪郊,垃圾回收回收不了蠕蚜。
python2上述代碼經(jīng)測試正常,但是python3報(bào)錯(cuò)悔橄。難道是python3改進(jìn)了波势?待確認(rèn),python3的del加gc回收 是否可以消除循環(huán)引用,答案是Python 3.4以后都可以自動(dòng)處理橄维。

另外尺铣,關(guān)于內(nèi)存泄漏的定位,還可設(shè)置gc為debug模式争舞,打印出不可回收對象凛忿,從而排查出可能發(fā)生內(nèi)存泄漏的對象。

# -*- coding:utf-8 -*-
import time,gc,objgraph

class Test(object):
    def __init__(self, name):
        self.__name = name

    def __del__(self):
        print("__del__ is called!")
# 創(chuàng)建對象

class L(list):
    def __del__(self):
        print('list')

def leak():
    objgraph.show_growth()
    a = Test("a")
    b = Test("b")
    # c=a
    a.attrb = b
    b.attra = a

    del a,b

    l1 = L([1,2])
    l2 = L([3,4])
    l1.append(l2)
    l2.append(l1)
gc.set_debug(gc.DEBUG_LEAK)
# gc.set_debug(gc.DEBUG_UNCOLLECTABLE)
leak()

print('----------')

objgraph.show_growth()

tracemalloc

tracemalloc 是python3內(nèi)置庫竞川,非常輕量店溢,可以用于追蹤內(nèi)存的使用情況,功能強(qiáng)大委乌,用法也很簡單床牧,遺憾的是python2不支持。https://docs.python.org/3/library/tracemalloc.html

例:

import tracemalloc

tracemalloc.start() # 開始跟蹤內(nèi)存分配

test = [i for i in range(100000)]

snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')  # lineno,逐行統(tǒng)計(jì)遭贸;filename戈咳,統(tǒng)計(jì)整個(gè)文件內(nèi)存
for stat in top_stats:
    print(stat)

結(jié)果:

/Users/mac/temp/makemoney_admin_flask/app/test.py:5: size=3533 KiB, count=99745, average=36 B

從結(jié)果來看,

文件第5行消耗了3533 KiB的內(nèi)存壕吹。

如果想統(tǒng)計(jì)某段程序的內(nèi)存情況著蛙,可以比較兩段快照之間的內(nèi)存,如下:

import tracemalloc

tracemalloc.start()
# ... start your application ...

snapshot1 = tracemalloc.take_snapshot()
test1 = [i for i in range(100000)]
test2 = [i for i in range(100000)]
# ... call the function leaking memory ...
snapshot2 = tracemalloc.take_snapshot()

top_stats = snapshot2.compare_to(snapshot1, 'lineno')

print("[ Top 10 differences ]")
for stat in top_stats[:10]:
    print(stat)

結(jié)果 :

/Users/mac/temp/makemoney_admin_flask/app/test.py:8: size=3532 KiB (+3532 KiB), count=99744 (+99744), average=36 B
/Users/mac/temp/makemoney_admin_flask/app/test.py:7: size=3532 KiB (+3532 KiB), count=99744 (+99744), average=36 B
/Users/mac/temp/makemoney_admin_flask/app/test.py:6: size=576 B (+576 B), count=1 (+1), average=576 B
/Users/mac/anaconda3/lib/python3.6/tracemalloc.py:387: size=96 B (+96 B), count=2 (+2), average=48 B
/Users/mac/anaconda3/lib/python3.6/tracemalloc.py:524: size=56 B (+56 B), count=1 (+1), average=56 B
/Users/mac/anaconda3/lib/python3.6/tracemalloc.py:281: size=40 B (+40 B), count=1 (+1), average=40 B

從打印結(jié)果得知耳贬,消耗內(nèi)存的程序段分布踏堡,可以知道哪些代碼消耗內(nèi)存較大,分析具體內(nèi)存泄漏的情況咒劲,非常有用顷蟆。

pympler

也是一種可以排查追蹤內(nèi)存泄漏的工具诫隅,參考文檔https://pythonhosted.org/Pympler/

# -*- coding:utf-8 -*-
from pympler import tracker


tr = tracker.SummaryTracker()

import time,gc,objgraph

class Test(object):
    def __init__(self, name):
        self.__name = name

    def __del__(self):
        print("__del__ is called!")
# 創(chuàng)建對象

class L(list):
    def __del__(self):
        print('list')

def leak():

    a = Test("a")
    b = Test("b")
    # c=a
    a.attrb = b
    b.attra = a

    # del a,b

    l1 = L([1,2])
    l2 = L([3,4])
    l1.append(l2)
    l2.append(l1)

# gc.set_debug(gc.DEBUG_UNCOLLECTABLE)
tr.print_diff()
leak()
print('----------')
tr.print_diff()

結(jié)果:

                       types |   # objects |   total size
============================ | =========== | ============
                        list |        3539 |    362.31 KB
                         str |        4148 |    297.93 KB
                        dict |          48 |     72.38 KB
                        code |         267 |     33.38 KB
                        type |          23 |     20.30 KB
                         int |         327 |      7.66 KB
            _sre.SRE_Pattern |          13 |      6.00 KB
                         set |           6 |      5.86 KB
                     weakref |          31 |      2.66 KB
                       tuple |          39 |      2.36 KB
           getset_descriptor |          24 |      1.69 KB
         function (__init__) |          13 |      1.52 KB
          wrapper_descriptor |          17 |      1.33 KB
  builtin_function_or_method |          11 |    792     B
                    property |           8 |    704     B
----------


                  types |   # objects |   total size
======================= | =========== | ============
                   list |         221 |     20.75 KB
                    str |         223 |     12.78 KB
                   dict |           2 |    560     B
     <class '__main__.L |           2 |    224     B
                    int |           8 |    192     B
  <class '__main__.Test |           2 |    128     B

主要看print('----------')之后的。

弱引用

弱引用模塊是weakref可以用于消除循環(huán)引用帐偎。

# -*- coding:utf-8 -*-
import time,gc,objgraph

import weakref

class Test(object):
    def __del__(self):
        print("del is called")

def callback(self):
    print("callback")

def leak():
    t1 = Test()
    t2 = Test()
    t1.arrt2 = weakref.proxy(t2)
    t2.arrt1 = weakref.proxy(t1)

leak()
gc.collect()
print(gc.garbage)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逐纬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子肮街,更是在濱河造成了極大的恐慌,老刑警劉巖判导,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫉父,死亡現(xiàn)場離奇詭異,居然都是意外死亡眼刃,警方通過查閱死者的電腦和手機(jī)绕辖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來擂红,“玉大人仪际,你說我怎么就攤上這事£侵瑁” “怎么了树碱?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長变秦。 經(jīng)常有香客問我成榜,道長,這世上最難降的妖魔是什么蹦玫? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任赎婚,我火速辦了婚禮,結(jié)果婚禮上樱溉,老公的妹妹穿的比我還像新娘挣输。我一直安慰自己,他們只是感情好福贞,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布撩嚼。 她就那樣靜靜地躺著,像睡著了一般挖帘。 火紅的嫁衣襯著肌膚如雪绢馍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天肠套,我揣著相機(jī)與錄音舰涌,去河邊找鬼。 笑死你稚,一個(gè)胖子當(dāng)著我的面吹牛瓷耙,可吹牛的內(nèi)容都是我干的朱躺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼搁痛,長吁一口氣:“原來是場噩夢啊……” “哼长搀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鸡典,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤源请,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后彻况,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谁尸,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年纽甘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了良蛮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悍赢,死狀恐怖决瞳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情左权,我是刑警寧澤皮胡,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站赏迟,受9級特大地震影響胸囱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瀑梗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一烹笔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抛丽,春花似錦谤职、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蒿柳,卻和暖如春饶套,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背垒探。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工妓蛮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人圾叼。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓蛤克,卻偏偏與公主長得像捺癞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子构挤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • python內(nèi)存管理是通過引用計(jì)數(shù)來實(shí)現(xiàn)的髓介。當(dāng)對象的引用計(jì)數(shù)為0時(shí),會被gc回收筋现。 為了探索對象在內(nèi)存的存儲唐础,我們...
    冬季戀歌1218閱讀 1,643評論 0 2
  • 1.元類 1.1.1類也是對象 在大多數(shù)編程語言中,類就是一組用來描述如何生成一個(gè)對象的代碼段矾飞。在Python中這...
    TENG書閱讀 1,253評論 0 3
  • 一元類 1類也是對象 在大多數(shù)編程語言中凰慈,類就是一組用來描述如何生成一個(gè)對象的代碼段汞幢。在Python中這一點(diǎn)仍然成...
    五行缺覺閱讀 1,039評論 0 1
  • [TOC] 內(nèi)存管理 一驼鹅、托管堆基礎(chǔ) 在面向?qū)ο笾形⑽剑總€(gè)類型代表一種可使用的資源,要使用該資源输钩,必須為代表資源的類...
    _秦同學(xué)_閱讀 3,779評論 0 3
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題豺型。內(nèi)存泄漏...
    apkcore閱讀 1,217評論 2 7