相信大家一定听过,看过甚至遇到过内存泄漏。在 .NET 平台也一定知道有垃圾回收器,它可以让开发人员不必担心内存的释放问题,因为它会自定管理内存。但是在 .NET 平台下进行编程,绝对不会发生内存泄漏的问题吗?答案是否定的,就算有了自动内存管理的垃圾回收器,也会发生内存泄漏。本文就讨论下 .NET 平台的垃圾回收器是如何工作的,进而当我们在编写 .NET 程序时避免发生内存泄漏的问题。

  > 垃圾回收的基本概念

  "垃圾"指的是事先分配过但后来不再被使用的内存。

  垃圾回收背后的一个基本观念是:"无限访问的内存",但是从来没有无限的内存,当机器需要分配内存但不够的时候,就需要把之前不再使用的内存--"垃圾"回收再利用。

  .NET 的垃圾回收器正是这样做的:

  .NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每当您创建新对象时,公共语言运行时都会从托管堆为该对象分配内存。只要托管堆中有地址空间可用,运行时就会继续为新对象分配空间。 但是,内存不是无限大的。最终,垃圾回收器必须执行回收以释放一些内存。(引用 MSDN 垃圾回收)

  > 垃圾回收器的工作场景

  每当我们创建一个对象的时候,系统会为新对象分配一块内存,如果有足够的可用内存则会直接分配;但是当内存不足的时候,此时垃圾回收器会进行一次回收操作,把不再使用的对象释放,转化为可用的内存供新对象使用。sat答案

  看似很简单的工作步骤,但是垃圾回收器怎么知道确保不再使用的对象的呢?

  > 垃圾回收算法

  当进行一次垃圾回收操作时,会分三个步骤进行:

  1. 先假设所有对象都是垃圾;

  2. 标记出正在使用的对象;

  标记依据:

  a. 被变量引用的对象,仍然在作用域中。

  比如某个类中的某个方法,方法执行了一半,如果此时发生垃圾回收,那么方法块中的变量都在作用域中,那么它们都会被标记为正在使用。

  b. 被另一个对象引用的对象,仍在使用中。

  3. 压缩:释放第二步中未标记的对象(不再使用,即"垃圾")并将使用中的对象转移到连续的内存块中。

  只要垃圾回收器释放了能释放的对象,它就会压缩剩余的对象,把它们都移回堆的端部,再一次形成一个连续的块。

  备注:

  垃圾回收器为了提升性能,使用了代机制,新建的对象是新一代,较早创建的对象是老一代,最近创建的对象是第0代。为了描述垃圾回收器的基本原理,本文不深入讨论代机制。

  总之,有了垃圾回收器,我们不必自己实现代码来管理应用程序所用的对象的生存期。

  既然有了自动内存管理功能的垃圾回收器,为什么还会发生内存泄漏呢?

  > 托管与非托管

  由公共语言运行库环境(而不是直接由操作系统)执行的代码称作托管代码,运行在 .NET 框架下,受 .NET 框架管理的应用或组件称作托管资源NET 中超过80%的资源都是托管资源,如 int, string, float, DateTime.

  非托管资源是 .NET 框架之外的,最常见的一类非托管资源就是包装操作系统资源的对象,例如文件,窗口或网络连接,对于这类资源虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。所以,对于非托管资源,在应用程序中使用完之后,必须显示的释放它们。托福答案

  所以,大部分内存泄漏都是非托管资源内存泄漏:没有显示的释放它们。

  > 非托管资源内存泄漏

  一个会导致内存泄漏的类:

  public class Foo

  {

  Timer _timer;

  public Foo()

  {

  _timer = new Timer(1000);

  _timer.Elapsed += _timer_Elapsed;

  _timer.Start();

  }

  void _timer_Elapsed(object sender, ElapsedEventArgs e)

  {

  Console.WriteLine("Tick");

  }

  }

  调用 Foo 类:

  static void Main(string[] args)

  {

  Foo foo = new Foo();

  foo = null;

  Thread.Sleep(int.MaxValue);

  }

  foo 虽然设置为 null,但是 foo 中的字段 _timer 依然存活,Elapsed 事件继续执行:

  此类中,_timer 对象就是非托管对象,由于 _timer 的 Elapsed 事件,.NET Framework 会保持 _timer 永远存活,进而 _timer 对象会保持 Foo 实例永远存活,直到程序关闭。

  为了解决这个问题,我们要显示的释放 _timer 对象:Foo 类继承 IDisposable 接口,修改后的类:

  public class Foo : IDisposable

  {

  Timer _timer;

  public Foo()

  {

  _timer = new Timer(1000);

  _timer.Elapsed += _timer_Elapsed;

  _timer.Start();

  }

  public void Dispose()

  {

  Console.WriteLine("Dispose");

  _timer.Dispose();

  }

  void _timer_Elapsed(object sender, ElapsedEventArgs e)

  {

  Console.WriteLine("Tick");

  }

  }

  再次调用 Foo 类,并显示调用 Dispose 方法:

  static void Main(string[] args)

  {

  Foo foo = new Foo();

  foo.Dispose();

  foo = null;

  Thread.Sleep(int.MaxValue);

  }

  foo 设置为 null,_timer 对象也同时被回收,Elapsed 事件停止:

.NET垃圾回收与内存泄漏的更多相关文章

  1. 深入理解Node.js中的垃圾回收和内存泄漏的捕获

    深入理解Node.js中的垃圾回收和内存泄漏的捕获 文章来自:http://wwsun.github.io/posts/understanding-nodejs-gc.html Jan 5, 2016 ...

  2. js垃圾回收和内存泄漏

    js垃圾回收和内存泄漏 js垃圾回收 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. 1.标记清除(常用) 工作原理:是当变量进入环境时,将这个变量标记为"进入环境& ...

  3. .NET 垃圾回收与内存泄漏

    > 前言相信大家一定听过,看过甚至遇到过内存泄漏.在 .NET 平台也一定知道有垃圾回收器,它可以让开发人员不必担心内存的释放问题,因为它会自定管理内存.但是在 .NET 平台下进行编程,绝对不 ...

  4. JavaScript中的垃圾回收和内存泄漏

    摘要: JS内存管理. 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 程序的运行需要内存.只要程序提出要求,操作系统或者运行时就必须供给内存.所谓的内存泄漏简单来说是不再用到的 ...

  5. js垃圾回收及内存泄漏

    js垃圾回收 js能够自动回收申请却未使用的内存,由于每次清除需要的性能较大,不是时时在刷新,而是每隔一段时间才进行一次. 回收的两种方式 标记清除(常用) 在内存中先标记变量,然后清除那些那些进入环 ...

  6. js垃圾回收与内存泄漏

    js垃圾回收机制 概念: javascript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中的使用的内存.而在C和C++之类的语言中,开发人员的一项基本任务就是手动跟踪内存的使用情况 ...

  7. 《JavaScript 闯关记》之垃圾回收和内存管理

    JavaScript 具有自动垃圾收集机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存.而在 C 和 C++ 之类的语言中,开发人员的一项基本 ...

  8. 深入了解C#系列:谈谈C#中垃圾回收与内存管理机制

    今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...

  9. C#中垃圾回收与内存管理机制

    今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...

随机推荐

  1. c语言小练习(蛮好玩的)

    1.求三个数的平均数,要求保留三位小数位 #include <conio.h> #include<stdio.h> int main(){ int a,b,c; float a ...

  2. 查错 CH Round #57 - Story of the OI Class

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2357%20-%20Story%20of%20the%20OI%20Class/查错 题解:刚开始看见立马以为是 ...

  3. HDOJ(HDU) 2132 An easy problem

    Problem Description We once did a lot of recursional problem . I think some of them is easy for you ...

  4. [转载]Web前端和后端之区分,以及面临的挑战

    原文地址:Web前端和后端之区分,以及面临的挑战[转]作者:joyostyle 在我们实际的开发过程中,我们当前这样定位前端.后端开发人员. 1)前端开发人员:精通JS,能熟练应用JQuery,懂CS ...

  5. SVM原理(1)

    SVM即支持向量机,是一种机器学习内的二类分类方法,是有监督学习方法. 首先我们需要建立一个分类任务: 首先考虑线性可分的情况:(所谓线性可分就是在N维空间上的两类点,可以用N-1个未知数的函数(超平 ...

  6. Android源码学习

    http://android-wheel.googlecode.com/svn/trunk/android-wheel-read-only 在github上面有一个叫做 android-wheel 的 ...

  7. 统计学习导论:基于R应用——第四章习题

    第四章习题,部分题目未给出答案 1. 这个题比较简单,有高中生推导水平的应该不难. 2~3证明题,略 4. (a) 这个问题问我略困惑,答案怎么直接写出来了,难道不是10%么 (b) 这个答案是(0. ...

  8. POJ 1686 Lazy Math Instructor (模似题+栈的运用) 各种坑

    Problem Description A math instructor is too lazy to grade a question in the exam papers in which st ...

  9. 文字保护纱-Material Design

    Ok,关于这个Material Design 都快被说烂了,他被开发者越来越熟悉的程度,却与市场上的单薄身影形成了鲜明的对比,以至于每当我提及Material Design时就像祥林嫂附身一样. 有些 ...

  10. Android(java)学习笔记195:学生信息管理系统案例(SQLite + ListView)

    1.首先说明一个知识点,通常我们显示布局文件xml都是如下: setContentView(R.layout.activity_main): 其实每一个xml布局文件就好像一个气球,我们可以使用Vie ...