面试题答案
一键面试代码设计方面
- 对象池技术:
- 对于频繁创建和销毁的对象,使用对象池模式。预先创建一定数量的对象并放入对象池中,当需要使用时从池中获取,使用完毕后再放回池中,而不是每次都创建新对象。例如,对于数据库连接对象,可以创建一个数据库连接池。在C#中,可以自己实现简单的对象池,如下代码示例:
public class ObjectPool<T> where T : class, new() { private Stack<T> _pool; private int _maxSize; public ObjectPool(int maxSize) { _pool = new Stack<T>(); _maxSize = maxSize; } public T GetObject() { if (_pool.Count > 0) { return _pool.Pop(); } return new T(); } public void ReturnObject(T obj) { if (_pool.Count < _maxSize) { _pool.Push(obj); } } }
- 复用现有对象:
- 在可能的情况下,尽量复用已有的对象而不是创建新对象。比如在处理字符串拼接时,使用
StringBuilder
对象,并且可以在方法内部复用同一个StringBuilder
实例,而不是每次拼接都创建新的StringBuilder
。
private static StringBuilder _stringBuilder = new StringBuilder(); public string ConcatenateStrings(string[] strings) { _stringBuilder.Clear(); foreach (var str in strings) { _stringBuilder.Append(str); } return _stringBuilder.ToString(); }
- 在可能的情况下,尽量复用已有的对象而不是创建新对象。比如在处理字符串拼接时,使用
- 减少不必要的对象创建:
- 避免在循环内部创建不必要的局部对象。例如,不要在循环中每次都创建新的
DateTime
对象来获取当前时间,如果只是需要获取一次当前时间,可以将其移到循环外部。
// 不好的做法 for (int i = 0; i < 1000; i++) { DateTime now = DateTime.Now; // 使用now进行一些操作 } // 好的做法 DateTime now = DateTime.Now; for (int i = 0; i < 1000; i++) { // 使用now进行一些操作 }
- 避免在循环内部创建不必要的局部对象。例如,不要在循环中每次都创建新的
资源分配方面
- 优化内存分配:
- 尽量使用值类型而不是引用类型,因为值类型在栈上分配内存,分配和释放的开销较小。例如,
int
(值类型)比Nullable<int>
(引用类型)在性能上更有优势,除非需要表示空值,否则应优先使用int
。 - 对于数组等大块内存的分配,尽量一次性分配足够的空间,避免多次动态扩容。例如,在初始化
List<T>
时,如果能提前知道大致的元素数量,可以使用带容量参数的构造函数:List<int> list = new List<int>(1000);
,这样可以减少内部数组扩容时的内存重新分配和数据复制开销。
- 尽量使用值类型而不是引用类型,因为值类型在栈上分配内存,分配和释放的开销较小。例如,
- 合理管理非托管资源:
- 对于使用非托管资源(如文件句柄、数据库连接等)的对象,要正确实现
IDisposable
接口,并在使用完毕后及时调用Dispose
方法释放资源。可以使用using
语句来确保资源的正确释放,如下代码示例:
using (FileStream fileStream = new FileStream("test.txt", FileMode.Open)) { // 使用fileStream进行文件操作 }
- 对于使用非托管资源(如文件句柄、数据库连接等)的对象,要正确实现
垃圾回收配置方面
- 了解垃圾回收模式:
- C#有不同的垃圾回收模式,如工作站垃圾回收(默认)和服务器垃圾回收。在高并发服务器场景下,如果服务器有多个CPU核心,可以考虑使用服务器垃圾回收模式。可以通过在应用程序配置文件(
app.config
或web.config
)中设置gcServer
为true
来启用服务器垃圾回收:
<configuration> <runtime> <gcServer enabled="true"/> </runtime> </configuration>
- C#有不同的垃圾回收模式,如工作站垃圾回收(默认)和服务器垃圾回收。在高并发服务器场景下,如果服务器有多个CPU核心,可以考虑使用服务器垃圾回收模式。可以通过在应用程序配置文件(
- 调整垃圾回收频率:
- 可以通过
GCSettings.LatencyMode
属性来调整垃圾回收的频率和延迟。例如,如果应用程序对响应时间要求较高,可以设置为GCLatencyMode.SustainedLowLatency
,这样垃圾回收器会尽量减少对应用程序的暂停时间,但可能会导致更多的内存占用。
GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency;
- 可以通过
- 强制垃圾回收时机:
- 虽然一般不建议手动调用垃圾回收(
GC.Collect()
),但在某些特定情况下,比如在应用程序启动或停止时,或者在大量对象不再使用且内存占用较高时,可以谨慎地调用GC.Collect()
来触发垃圾回收,以释放内存。例如:
// 在应用程序停止时 protected override void OnStop() { GC.Collect(); GC.WaitForPendingFinalizers(); base.OnStop(); }
- 虽然一般不建议手动调用垃圾回收(