網站首頁 編程語言 正文
".NET的堆和棧"系列:
ASP.NET堆和棧一之基本概念和值類型內存分配
ASP.NET堆和棧二之值類型和引用類型參數傳遞和內存分配
ASP.NET堆和棧三之引用類型對象拷貝和內存分配
ASP.NET堆和棧四之對托管和非托管資源垃圾的回收和內存分配
在"?ASP.NET堆和棧一之基本概念和值類型內存分配"中,了解了"堆"和"棧"的基本概念,以及值類型的內存分配。我們知道:當執行一個方法的時候,值類型實例會在"棧"上分配內存,而引用類型實例會在"堆"上分配內存,當方法執行完畢,"棧"上的實例由操作系統自動釋放,"堆"上的實例由.NET Framework的GC進行回收。
在"?ASP.NET堆和棧二之值類型和引用類型參數傳遞和內存分配"中,我們了解了值類型參數和引用類型參數在傳遞時的內存分配情況。
在"?ASP.NET堆和棧三之引用類型對象拷貝和內存分配"中,我們了解了在拷貝引用類型對象時的內存分配情況。
而本篇的重點要放在:對托管和非托管資源的垃圾回收、處理以及內存分配情況。
什么樣的對象被GC認為是垃圾?
當托管堆中的對象不被任何其它對象所引用,這些對象將成為被釋放的垃圾對象等待被GC回收。
每個應用程序都有一組根指針,這些根指針是不會被回收的,是由JIT編譯器和CLR運行時維護的一個列表。主要包括:
- 全局/靜態指針:指向全局或局部靜態變量
- 棧指針:指向應用程序線程所需要的那部分棧上空間
- 寄存器指針:指向托管堆所需要的那部分CPU中的內存地址
以上,假設托管堆中有5個對象,1和5被跟指針引用,3依賴1,那么在這組托管堆對象中,2和4被回收后變成如下:
當運行時有新的引用對象產生,將會被放到托管堆中這組對象的最上面。
GC如何回收?
GC對托管堆中對象的回收
GC采用一定的算法在托管堆中遍歷所有對象,最終形成一個可達對象和不可達對象,不可達對象將被回收。
GC對非托管堆中對象的回收、處理
對資源的回收
比如文件、數據庫鏈接、網絡鏈接等,這些不再托管堆中的對象如何被回收呢?
1、通過析構函數回收
public class Sample
{
//析構函數
~Sample()
{
}
}
在托管堆中,那些帶有析構函數的實例,將被放置到"Finalization Queue"中。
對于那些不被任何其它對象所引用,如果沒有析構函數,比如2,將被直接回收,如果有析構函數,例如4,會被放到"Freachable Queue"中,等待GC實施下一輪回收。
當為一個類添加析構函數后,為GC增加了額外的工作,代價是比較昂貴的,更現實的做法是讓類來實現IDisposable接口。
2、通過實現IDisposable接口回收
首先讓一個類實現IDisposable接口。
public class ResourceClass : IDisposable
{
public void Dispose()
{
//TODO:實現回收邏輯
}
}
在應用程序中調用如下實施回收。
using(ResourceClass re = new ResourceClass())
{
}
對靜態值類型變量的處理
class Counter
{
private static int s_Number = 0;
public static int GetNextNumber()
{
int newNumber = s_Number;
// DO SOME STUFF
newNumber += 1;
s_Number = newNumber;
return newNumber;
}
}
如上,當方法有方法處理靜態字段就需要注意了,2個線程同時調用GetNextNumber()會得到相同的結果,而我們的本意是:每調用一次方法,靜態字段s_Number自增1。
我們可以在處理邏輯塊中加鎖,每次只允許一個線程執行。
class Counter
{
private static int s_Number = 0;
public static int GetNextNumber()
{
lock (typeof(Counter))
{
int newNumber = s_Number;
// DO SOME STUFF
newNumber += 1;
s_Number = newNumber;
return newNumber;
}
}
}
對靜態引用類型變量的處理
class Olympics
{
public static Collection<Runner> TryoutRunners;
}
class Runner
{
private string _fileName;
private FileStream _fStream;
public void GetStats()
{
FileInfo fInfo = new FileInfo(_fileName);
_fStream = _fileName.OpenRead();
}
}
以上,在GetStats()方法中,由于沒有對FileStream及時關閉,如果Olympics恰巧有10萬個Runner的集合,10萬Runner都執行沒有關閉FileStream的Gettats()方法,這將是一場災難!
Singleton模式可以很好地避免上述問題,它保證了在任何時候,內存中只存在某個類的一個實例。
public class Earth
{
private static Earth _instance = new Earth();
private Earth(){}
public static Earth GetInstance(){return _instance;}
}
以上,單例模式的必要構成要素包括:
1、私有靜態引用類型變量
2、私有構造函數
3、獲取類實例的靜態方法
GC何時回收?
GC會周期性地執行垃圾回收、內存清理工作,以下情況會啟動GC:
- 托管堆內存不足溢出時
- 調用GC.Collect()方法強制執行垃圾回收
- Windows報告內存不足
- CLR卸載AppDomain
GC回收之后,又執行哪些操作?
GC在垃圾回收之后,托管堆上將出現多個被收集對象的"空洞",為了避免托管堆的內存碎片,會重新分配內存、壓縮托管堆。
原文鏈接:https://www.cnblogs.com/darrenji/p/3849306.html
相關推薦
- 2022-08-20 python操作csv格式文件之csv.DictReader()方法_python
- 2022-04-06 Python的type函數結果你知道嘛_python
- 2022-11-21 Android性能優化之JVMTI與內存分配_Android
- 2022-03-13 C語言之直接插入排序算法的方法_C 語言
- 2022-11-14 Python?prettytable模塊應用詳解_python
- 2022-08-05 Redis實現分布式鎖的五種方法詳解_Redis
- 2022-04-28 C++Stack棧類模版實例詳解_C 語言
- 2022-06-08 Jenkins集成Gitlab實現自動化部署的全過程記錄_相關技巧
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支