成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

編譯器的自動內存管理,靜態的GC算法

開發 前端
寫過C語言的都知道,多線程的野指針是非常難查的BUG,因為程序跑飛了不知道會core在哪里,而且BUG也不是必現的。

?C語言幾乎唯一的缺點就是,需要手動管理內存。

拋開這點之外,我覺得其他語言都不如C語言?。

所以,雖然自動內存管理比較復雜,但我還是給scf編譯器框架加了靜態的GC算法。

在編程方面,自動內存管理一般叫GC算法,是英文Garbage Collection的縮寫。

棧內存的管理比較簡單,是由編譯器根據函數調用鏈而自動管理的。

堆內存的管理,在C語言里是由程序員手動管理的。

因為程序員管理錯了堆內存而導致的BUG,是C語言最常見、也最難搞的BUG。

所以,后來的編程語言都對內存管理做了簡化,例如C++的智能指針。

C++的智能指針,是一種半自動的內存管理機制:

它把一個堆內存的指針放在一個類的成員變量里,利用局部對象離開作用域時的析構函數,來完成堆內存的釋放。

所以C++的效率比其他語言快得多,因為局部對象什么時候離開作用域,是可以在編譯時就確定的,不需要在運行時做額外的處理。

也就是說,C++的智能指針是靜態的GC算法。

在編譯時就處理好的算法,是靜態的算法。

在運行時才會處理的算法,是動態的算法。

動態的算法依賴于運行時狀態,對程序的速度有較大的影響:

  • 因為框架在處理對象內存的回收時,用戶程序不得不暫停,
  • 否則兩邊發生競爭條件,那就是跟C語言的野指針一樣的BUG。

寫過C語言的都知道,多線程的野指針是非常難查的BUG,因為程序跑飛了不知道會core在哪里,而且BUG也不是必現的。

為什么程序員怕有主控軟件的交通工具?

因為程序員知道多線程+競爭條件+野指針 == 隨機crash + 事后找不到第一現場?

動態的GC算法,為了避免出現第2種情況,那就只能使用第1種情況。

1、GC算法有必要是動態的嗎?

實際上沒必要,否則C語言怎么手動管理內存的。

C語言的free()代碼肯定是在編譯之前就寫好了的!

只要寫對了free()位置,C語言既不會出BUG,也不會內存泄漏。

所以,編譯器只要代替程序員添加free(),就可以自動管理內存了。

free()的添加位置,當然是在變量離開作用域時。

如上圖:

有4個對象變量m0, m1, m2, m3,

main()函數返回時也是它們離開作用域的時候,所以在main函數的結尾自動添加釋放代碼,程序員就不用手動釋放內存了。

2、怎么檢測變量什么時候離開作用域?

在編譯器的后端:

1)代碼的每個基本塊都是流程圖上的一個節點,

2)基本塊之間通過跳轉聯系起來,

3)基本塊內部的代碼是順序運行的。

所以,釋放內存的代碼需要加在兩個基本塊之間。

上述main()函數的流程圖

上圖是前面的main()函數的流程圖。

創建一個對象分兩步:第一步調用malloc()申請內存,第二步調用構造函數__init()初始化內存。

(為了簡化代碼,我沒有做返回值為NULL的檢查)

在第8個基本塊 m3 = m0 + m1 + m2 之后,m0, m1, m2 就不再使用了,也就是它們3個離開作用域了。

即使在源代碼層面這時m0, m1, m2依然處于main()函數的作用域內,但對后端來說它們已經離開作用域了,因為之后的基本塊都不再使用它們了。

所以,對m0, m1, m2的釋放代碼,應該加在第8和第9號基本塊之間。

第9號基本塊會把指針 m3->data 賦值給dd,這會讓(m3->data)內存的引用計數+1。

對m3的釋放代碼可以放在第9和第10之間,之后不會再使用m3了:這會讓m3->data的引用計數-1。

這時,內存數據有且只有1個引用計數(一開始自帶1個),同時有且只有指針dd指向它。

指針dd的釋放在for循環之后,即第10和11之間:這里的釋放會讓引用計數減少到0。

在引用計數為0時,要調用free()函數,把內存還給系統。

GC算法的要點有3個:

1)什么時間調用的malloc(),

2)什么時間有指針的賦值,要把引用計數+1,

3)什么時間離開作用域,也就是后續不再使用對象變量,要把引用計數-1,如果減少之后為0,就調用free().

3、跨函數的指針分析,

有時候,申請的內存并不會在當前函數內釋放,而是返回給更上層的主調函數。

這時的GC算法,就需要跨越函數的調用鏈,進行指針分析。

mat類的構造函數__init()

前面的mat對象的成員指針 m3->data,就是需要跨函數分析的指針。

它是在構造函數里申請的內存,因為是成員變量,所以要在析構函數里釋放。

如果是局部變量,就在當前函數內釋放:因為局部變量的作用域就是當前函數。

mat類的聲明,成員變量部分

成員變量的有效時間,是伴隨著當前對象的。

局部變量的有效時間,是伴隨著當前函數的。

成員變量在構造函數返回時依然有效,所以要把它是malloc()申請的這個信息,傳遞到更上層的函數。

這樣:

1)在main()里才知道它是malloc()申請的,

2)在 dd = m3->data 時才知道給它指向的內存引用計數+1,

3)在釋放m3時,析構函數把引用計數-1之后,引用計數才不為0:內存依然是有效的,這時指針dd依然指向它。

否則,dd就是野指針了!

mat類的析構函數__release()

函數調用鏈,在語義分析時是很容易確定的。

抽象語法樹AST上的每一個函數調用,必然有一個主調函數、有一個被調函數。

主調和被調,構成了整個程序的函數調用圖:

最頂層的是main()函數,最底層的是malloc()函數。

以malloc為起點、main為終點,做圖的寬度優先搜索,就可以獲取整個調用鏈。

然后從離malloc最近的函數開始,一層層的分析就行了。

函數調用圖

一定是用圖的寬度優先搜索(BFS)!

不能用深度優先搜索(DFS),因為一個上層函數可能調用多個下層函數,而這多個下層函數里都malloc了內存。

如上圖:

如果是DFS,分析順序是A->D,這樣D調用B而申請的內存就會被漏過去了。

如果是BFS,分析順序是A->B->C->D->E,這樣任何函數申請的內存如果傳遞給上層,(在分析上層函數時)都不會被漏過去。

4、遞歸調用的指針分析

上圖的C()和E()之間的互相調用構成遞歸,表現為函數調用圖上的回路。

這種情況下,兩個函數里申請的內存會互相傳遞,屬于最復雜的一種情況!

在編譯器里的處理方法是:

do {
delivery = check_delivery();
} while (0 == delivery);

用do while循環檢查內存的傳遞情況,記錄傳遞的變量和計數,直到不再發生變化為止。

最后,就是在合適的位置添加free()代碼了:

最后的總是最簡單的,the last is the simplest.

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2010-02-02 17:08:26

Python靜態編譯器

2010-02-02 17:08:26

Python靜態編譯器

2019-12-10 08:59:55

JVM內存算法

2010-10-20 13:43:37

C++編譯器

2022-05-18 09:31:42

編譯器開源代碼生成

2010-03-23 11:17:16

Python 動態編譯

2010-01-12 16:42:59

C++編譯器

2010-01-14 16:46:13

CentOS Mysq

2016-11-08 18:53:08

編譯器

2020-01-10 18:04:01

Python編程語言Windows

2010-01-18 10:34:21

C++編譯器

2010-01-21 09:11:38

C++編譯器

2009-08-10 17:12:54

C#編譯器

2017-03-20 18:01:55

編譯器匯編

2013-03-29 10:02:37

編譯器語言編譯開發

2022-05-27 08:01:36

JVM內存收集器

2009-05-05 09:55:10

Javastring對象

2013-10-31 10:44:54

IDE工具

2010-01-08 16:00:46

C++編譯器

2012-04-05 09:13:17

C代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产一区二区电影 | 日韩视频在线观看一区二区 | 男女免费观看在线爽爽爽视频 | 免费的色网站 | 精品久久久久久久久久久 | japanhdxxxx裸体| 亚洲日本成人 | 欧美一级淫片免费视频黄 | 91亚洲国产 | 成人免费视频网站在线看 | 鲁视频 | 一区二区三区四区av | 欧美国产精品 | 亚洲精品在线91 | 偷拍自拍第一页 | 久久久久久成人网 | 亚洲精品一二区 | 天天躁日日躁狠狠很躁 | 国产91久久精品一区二区 | 久久大陆| 色视频在线播放 | 成人性视频在线 | 精品国产一区二区三区久久久四川 | 成人免费av | 男女在线免费观看 | 野狼在线社区2017入口 | 亚洲精品免费在线 | 一本大道久久a久久精二百 欧洲一区二区三区 | 亚洲成人av | 蜜桃特黄a∨片免费观看 | 中文字幕第一页在线 | 午夜久久av| 99久久精品国产毛片 | 久久综合一区 | 中文在线视频观看 | 欧美一区永久视频免费观看 | 国产一区二区影院 | 91精品久久久久久久久久入口 | 国产精品s色 | 国产在线网站 | 99热国产在线播放 |