-
語言類型
python是一種基於解釋器的語言,解釋器會逐行讀取代碼;首先將python編譯成字節碼,然後由C程序解釋.
C++是一種編譯語言,在其他章節裏寫過,整個過程是編譯器編譯代碼成彙編語言,彙編語言由彙編器生成機器碼,之後還要經過鏈接器載入文件\庫等指令生成可執行代碼,最後裝載器將可執行代碼和數據載入內存,CPU讀取內存執行. -
內存管理
python由自動垃圾收集器進行內存管理.
c++中程序員必須自己進行內存管理. -
速度
python由全局鎖,多線程效果不好
c++運行效率很高
python 垃圾回收機制
- 引用計數
python的垃圾回收機制主要是引用計數爲主,分代回收爲輔. 引用計數就是每個對象維護一個ob_refcnt,用來記錄當前對象被引用的次數.
當出現下面的情況時引用+1:
- 對象被創建 a=1
- 對象被引用 c=b
- 對象被當作參數傳入函數中 func(a)
- 對象被作爲元素存儲在容器中時 List=[a,b] Dict={a:1}
下面四種情況引用減一:
- 當對象被顯式銷燬 del a
- 當對象被賦予新的對象 a=2
- 當對象離開作用域,如func執行完之後,函數內的局部遍歷引用計數器就都會減一
- 當元素從容器中刪除或者容器被銷燬
當計數器減到0,那麼該內存就會被python虛擬機銷燬.
缺點:
- 消耗資源,需要維護計數器的資源.
- 無法解決循環引用的問題,和shared_ptr一樣出現了循環引用無法正常回收
list1=[]
list2=[]
list1.append(list2)
list2.append(list1)
上面的結果是 list1=[[[[[…]]]]] list2=[[[[[…]]]]]
- 標記刪除
『標記清除(Mark—Sweep)』算法是一種基於追蹤回收(tracing GC)技術實現的垃圾回收算法。它分爲兩個階段:第一階段是標記階段,GC會把所有的『活動對象』打上標記,第二階段是把那些沒有標記的對象『非活動對象』進行回收。那麼GC又是如何判斷哪些是活動對象哪些是非活動對象的呢?
對象之間通過引用(指針)連在一起,構成一個有向圖,對象構成這個有向圖的節點,而引用關係構成這個有向圖的邊。從根對象(root object)出發,沿着有向邊遍歷對象,可達的(reachable)對象標記爲活動對象,不可達的對象就是要被清除的非活動對象。根對象就是全局變量、調用棧、寄存器。
這個方法就是通過根節點找出可達和不可達的節點組,不可達的節點組就是相互引用或者等待釋放的.
在上圖中,我們把小黑圈視爲全局變量,也就是把它作爲root object,從小黑圈出發,對象1可直達,那麼它將被標記,對象2、3可間接到達也會被標記,而4和5不可達,那麼1、2、3就是活動對象,4和5是非活動對象會被GC回收。
標記清除算法作爲Python的輔助垃圾收集技術主要處理的是一些容器對象,比如list、dict、tuple,instance等,因爲對於字符串、數值對象是不可能造成循環引用問題。
- 分代回收
首先建立了一個鏈表,把創建的對象都加入,這個鏈表是Generation Zero.
隨後,Python會循環遍歷零代列表上的每個對象,檢查列表中每個互相引用的對象,根據規則減掉其引用計數。減到0的對象就可以被釋放,不是0的對象就會被移動到一代鏈表中.
循環上面的過程,如果一代鏈表中存活下來的就會被放入二代鏈表.
這個循環遍歷多久執行一次呢? 根據一個GC閾值來判斷,即當分配的計數器計數到某個閾值就開始遍歷.
分代的好處: 保留了長期留存的對象,這些對象就大概率很久纔會被釋放,因此遍歷的頻次可以減少.
這種行爲的理論是弱代假說年親的對象通常死得也快,而老對象則很有可能存活更長的時間。
將系統中的所有內存塊根據其存貨的時間劃分爲不同的集合, 每個集合就成爲一個”代”, 垃圾收集的頻率隨着”代”的存活時間的增大而減小(活得越長的對象, 就越不可能是垃圾, 就應該減少去收集的頻率)