# [Python] GC(Garbage Collection)垃圾回收機制/Middleware/JWT ###### tags: `後端` ## GC(Garbage Collection)垃圾回收機制 在CPython裏頭,對於記憶體處理有兩種做法: 1. Reference counting 2. Generational garbage collection(i.e. GC模組) 首先,第一種方法是**Reference counting(引用計數)**,透過`標記-清理`來釋放記憶體。 >在python裏頭當某個物件被參考到,該物件的reference count就會+1,反之,當不被參考到的時候則會-1,**一旦該物件的reference count減到為0,該物件的記憶體將會被釋放回收。** 透過`sys.getrefcount()`的方式可以觀察到reference count的數量變化,如下 ``` import sys a = [1,2,3] b = a sys.getrefcount(a) # 3 # 第一次是建立a # 第二次是b參考到a # 第三次是傳入getrefcount() ``` Reference counting 的缺點是遇到 **reference cycle(迴圈引用)** 的問題時無法解決。所謂 reference cycle(迴圈) 是底下的情境: ``` class MyClass(object): pass a = MyClass() a.obj = a del a ``` 我們建立一個以MyClass類別為模板的物件a,並把a的屬性obj指向a,當執行`del a`的時候,**a其實不會消失,因為a永遠參考到自己,所以reference count永遠不會等於0,這個問題就是 reference cycle(迴圈)。** Python 中使用 **`標記-清除`的方式來解決迴圈引用** 導致的問題。 `標記-清除`演算法在進行垃圾回收時分成了兩步: 1. `標記`階段,遍歷所有的物件,如果是可達的(reachable),也就是還有物件引用它,那麼就標記該物件為可達 2. `清除`階段,再次遍歷物件,如果發現某個物件沒有標記為可達,則就將其回收。 **引用計數+`標記-清除`** 的方式實現了 Python 垃圾回收,但整個過程比較慢,而且在`標記-清除`過程中還需要暫停整個程式。 接著,第二種方法是 **Generational garbage collection(分代回收)**,也就是python的**GC模組**,以 `空間換時間` 的方式來提高垃圾回收的效率,可以解決上述提到的 reference cycle(迴圈)的問題。 中心思想是: >**物件存在時間越長,越可能不是垃圾,應該越少去收集。** 這樣在執行標記 - 清除演算法時可以有效減小遍歷的物件數,從而提高垃圾回收的速度 1. GC有**三個generation**,**每次掃描時如果存活下來就會移到下一個generation**,以此類推。 >**The garbage collector is keeping track of all objects in memory.** > >A new object starts its life in the **first generation** of the garbage collector. **If Python executes a garbage collection process on a generation and an object survives, it moves up into a second, older generation.** The Python garbage collector has three generations in total, and **an object moves into an older generation whenever it survives a garbage collection process on its current generation.** 2. GC有**門檻值(threshold)**,當某一世代被分配的物件與被釋放的物件之差達到某一閾值的時候,就會觸發 gc 對某一世代的掃描。**當某一世代的掃描被觸發的時候,比該世代年輕的世代也會被掃描** >For each generation, the garbage collector module has a **threshold number of objects.** **If the number of objects exceeds that threshold, the garbage collector will trigger a collection process.** For any objects that survive that process, they’re moved into an older generation. * [Python Garbage Collection: What It Is and How It Works](https://stackify.com/python-garbage-collection/) ## Middleware(中介軟體) **中介軟體**: >In a web application, **middleware can be described as a function or set of functions that get executed before the request is being handed over to a controller.(在request送交回去給controller以前執行的一些函數,就稱為Middleware,中介軟體)** > >One very common use case is to **authorize a request based on some auth header or a JWT cookie.(常見的情境是應用在驗證使用者資訊)** > >是一些**有權存取要求物件 (req)、回應物件 (res) 和應用程式要求/回應循環中之下一個中介軟體函數的函數**。下一個中介軟體函數通常以名為 next 的變數表示。 Express 就是一個本身功能極簡的路由與中介軟體 Web 架構:本質上,**Express 應用程式是一系列的中介軟體函數呼叫。** 如果現行中介軟體函數不會結束要求/回應循環,它必須呼叫 next(),以便將控制權傳遞給下一個中介軟體函數。否則,要求將會停擺。 <補充> **JWT(Json Web Token)**: >**有限時間內**可利用**認證令牌**要求對應的操作權限 1. 符合設計 RESTful API 時 **Stateless 無狀態** 原則 2. 意味著每一次從客戶端(Client)向伺服器端(Server)發出的請求都是獨立的,**使用者經驗證後,在伺服器端不會將用戶驗證狀態透過 Session 儲存起來(減少資料庫的花費成本與查詢效能)** 3. 每次客戶端發出的請求都將帶有伺服器端需要的所有資訊 — **從客戶端發出給伺服器端的請求將帶有 JWT 字串表明身份 。** 參考資料: * [[筆記] 透過 JWT 實作驗證機制](https://medium.com/%E9%BA%A5%E5%85%8B%E7%9A%84%E5%8D%8A%E8%B7%AF%E5%87%BA%E5%AE%B6%E7%AD%86%E8%A8%98/%E7%AD%86%E8%A8%98-%E9%80%8F%E9%81%8E-jwt-%E5%AF%A6%E4%BD%9C%E9%A9%97%E8%AD%89%E6%A9%9F%E5%88%B6-2e64d72594f8) * [Creating Middlewares with Python Flask](https://medium.com/swlh/creating-middlewares-with-python-flask-166bd03f2fd4)