Files
My-Notes/笔记/CSharp/核心/构造函数、析构函数、垃圾回收.md
T
2026-06-21 09:51:55 +08:00

181 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 构造函数
概念:
- 构造函数用于在对象创建时做初始化
- 构造函数名必须和类名相同
- 构造函数没有返回值类型
- ==可以重载==
通常用法:
- 给字段或属性设置初始值
- 保证对象一创建出来就处于可用状态
语法:
```csharp
访问修饰符 类名(参数列表)
{
}
```
案例:
```csharp
class Person
{
public string Name;
public int Age;
public Person()
{
Name = "默认值";
Age = 0;
}
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
```
`this` 调用其他构造函数:
```csharp
class Person
{
public string Name;
public int Age;
public Person() : this("默认值", 0)
{
}
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
```
注意:
1. ==如果类里完全没写任何实例构造函数,编译器才会自动补一个无参构造函数==
2. ==只要你自己写了任意实例构造函数,默认无参构造函数就不会再自动生成==
3. 构造函数通常写 `public`,但也可以根据设计写成 `private` / `protected`
4. 子类构造函数可以通过 `base(...)` 调用父类构造函数
----
# 析构函数
概念:
- C# 里的析构函数更准确地说是==终结器(finalizer==
- 当对象即将被 GC 回收时,运行时可能会调用它
- 它主要用于“兜底清理非托管资源”
语法:
```csharp
class Person
{
~Person()
{
// 清理代码
}
}
```
注意:
1. 析构函数只能写在==类==里,结构体不能写
2. 不能手动直接调用析构函数
3. 析构函数执行时机==不确定==
4. 大多数业务代码里==不推荐为了练习而滥写析构函数==
5. 现代 .NET 中,更常见的做法是优先使用 `IDisposable``using``SafeHandle`
----
# 垃圾回收
垃圾回收(GC):
- GC 是 .NET 的自动内存管理机制
- 它负责识别哪些托管对象还“活着”,哪些已经不可达,可以回收
基础理解:
1. 只要对象还能从“根”访问到,就一般不会被回收
2. 访问不到的对象,才有机会被 GC 回收
3. GC 主要管理的是==托管堆上的对象==
分代概念:
- .NET GC 常分为 0、1、2 代
- 新对象一般先进入 0 代
- 活得越久,越可能被提升到更高代
- 大对象通常会进入 LOH(大对象堆),阈值常见记法是 >= `85,000` 字节
注意:
1. ==`GC.Collect()` 一般不建议手动乱调==
2. 手动触发 GC 可能带来性能抖动
3. “值类型一定在栈上、引用类型一定在堆上”不是绝对规则
4. GC 解决的是==托管内存==问题,不等于所有资源都会自动及时释放
----
# GC 和 IDisposable
首先区分资源类型:
- **托管资源**
比如普通对象、字符串、集合。主要由 GC 管理。
- **非托管资源**
比如文件句柄、数据库连接、Socket、窗口句柄。需要更及时地手动释放。
为什么要用 `IDisposable`
- 因为 GC 只负责“对象内存”回收
- 但像文件、连接、句柄这类资源,经常需要你主动关闭
最常见写法:
```csharp
using var stream = new FileStream("demo.txt", FileMode.OpenOrCreate);
// 使用 stream
```
说明:
- `using` 结束时会自动调用 `Dispose()`
- 这比“等 GC 什么时候想起来再收”更可靠
标准释放模式示意:
```csharp
public class MyResource : IDisposable
{
private bool _disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// 释放托管资源
}
// 释放非托管资源
_disposed = true;
}
~MyResource()
{
Dispose(false);
}
}
```
补充理解:
1. `Dispose()` 是“我现在就主动释放”
2. 析构函数是“万一你忘了,我最后帮你兜底一次”
3. `GC.SuppressFinalize(this)` 的意思是:
这个对象已经手动释放好了,不用再走终结器那一套
复习重点:
- GC 管托管内存
- `Dispose` 管需要及时释放的资源
- 最常用姿势不是手写 `GC.Collect()`,而是优先写好 `using` / `Dispose`
#封装
#核心