写了一个window服务,循环更新sqlite记录,内存一点点稳步增长。三天后,内存溢出。于是,我从自己的代码入手,查找到底哪儿占用内存释放不掉,最终明确是调用servicestack.ormlite更新sqlite数据库造成的。至于是不是框架问题,可能性不大,因为本地模拟执行的代码没有任何问题。我觉得应该是orm在执行数据库更新后,对象还在被引用造成的。这里,我贴出一个伪代码:

//存放对象的一个列表
static List<Record> data=new List<Record>(); while(true){ var models = ReadDB();
data.AddRange(models);
//更新model对象的字段
Dbhelp.UpdateAll(models);
data.Clear();
}

我的猜测到底对不对呢?现在还不知道。不过在探寻答案的时候,对GC的相关机制详细地了解了一遍。

一、什么是GC?

官网中有这么一句话:

The garbage collector is a common language runtime component that controls the allocation and release of managed memory。

原来GC是CLR的一个组件,它控制内存的分配与释放。

二、托管堆和CLR堆管理器

我们知道c#中的引用类型,分配在堆上。所谓的堆,就是一大块连续的内存地址。CLR堆管理器负责内存的分配、释放。堆又分为小对象堆和大对象堆。它的内存分配流程如下:

图片来源《.NET高级调试》pdf

CLR加载时,就会分配堆。

 三、GC的工作机制

 GC有三个假设:

1、如果没有特别声明,所有的对象都是垃圾(通过引用追踪对象是否为垃圾)

2、假设托管堆上所有的对象的活跃时间都是短暂的(相对于长久活跃的对象来说,GC将更频繁地收集短暂活跃的对象)

3、通过代跟踪对象的持续时间

以下是官方文档给出的和这三个假设一致

The garbage collector in the common language runtime supports object aging using generations

Objects created more recently are part of newer generations, and have lower generation numbers than objects created earlier in the application life cycle.

Objects in the most recent generation are in generation 0. This implementation of the garbage collector supports three generations of objects, generations 0, 1, and 2

每代都有自己的堆,假如0代的堆满了,就会触发GC,然后把依然有引用的对象升级,放到1代对象。最后压缩堆,把剩余的堆空间合并到一块。1代对象也是如此操作。但到了2代,就处理不同了。2代的堆可能是大对象堆,它的压缩代价过于高昂,所以只是合并相邻的空间。

图片来源博客园c#技术漫谈之垃圾回收(GC)

Garbage collection happens automatically when a request for memory cannot be satisfied using available free memory

GC发生的时机,就是相应的堆达到了阈值,因为堆也有大小限制,并不是无限的。尽管2代堆或者大对象堆满的时候,通过增加新的内存段来满足内存分配,如果没有可用的内存,这时就会报内存溢出。

四、GC不能释放非托管资源

有两种情况,第一种:托管代码引用了非托管资源,比如文件操作、数据库连接、网络连接等。这时候必须手动释放,或实现 dispose模式,或实现对象终结 。第二种:非托管代码使用了托管代码。这种情况,GC是可以回收托管对象的,因为它检测不到非托管代码的引用。

When a type uses unmanaged resources that must be released before instances of the type are reclaimed, the type can implement a finalizer.

In most cases, finalizers are implemented by overriding the Object.Finalize method; however, types written in C# or C++ implement destructors, which compilers turn into an override of Object.Finalize

必须注意的一点是,实现对象终结器,GC会在释放对象之前自动调用。其实这是一个代价非常高昂的备用机制。所以能自己释放非托管资源的,就自己释放。

如果一个对象中包含有终结器,那么在new的时候放入到终结者队列。当GC会把这个对象标为垃圾时,放入到另一个队列F-Reachable中。这个队列包含了所有带有终结器并且将被作为垃圾收集的对象,这些对象的终结器都将被执行。在垃圾收集的过程总并不会执行终结器代码。而是由.NET 进程的终结线程调用。因此,此时的垃圾回收滞后一段时间,目的在于等待终结器代码执行的完成。

五、dispose模式

 using System;

 class BaseClass : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false; // Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} // Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return; if (disposing) {
// Free any other managed objects here.
//
} // Free any unmanaged objects here.
//
disposed = true;
} ~BaseClass()
{
Dispose(false);
}
}
 using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices; class DerivedClass : BaseClass
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a SafeHandle instance.
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true); // Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return; if (disposing) {
handle.Dispose();
// Free any other managed objects here.
//
} // Free any unmanaged objects here.
// disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}

这是基类和子类的dispose模式,来源于官网。

浅谈c#垃圾回收机制(GC)的更多相关文章

  1. 浅谈 JavaScript 垃圾回收机制

    github 获取更多资源 https://github.com/ChenMingK/WebKnowledges-Notes 在线阅读:https://www.kancloud.cn/chenmk/w ...

  2. 浅谈python垃圾回收机制

    引入 ​ 解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题,当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉,那 ...

  3. 浅谈java垃圾回收机制

    今天看thinking in java,里面很详细的谈到java垃圾回收器机制,看完后让我对这神秘的区域有一定的了解,特写一些小总结记录下来. 分两点来说. 第一点:Object.finalize() ...

  4. 垃圾回收机制GC知识再总结兼谈如何用好GC(转)

    作者:Jeff Wong 出处:http://jeffwongishandsome.cnblogs.com/ 本文版权归作者和博客园共有,欢迎围观转载.转载时请您务必在文章明显位置给出原文链接,谢谢您 ...

  5. 垃圾回收机制GC知识再总结兼谈如何用好GC

    一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...

  6. 垃圾回收机制GC知识再总结兼谈如何用好GC(其他信息: 内存不足)

    来源 图像操作,易内存泄露,边界像素 一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对 ...

  7. .NET 之 垃圾回收机制GC

    一.GC的必要性 1.应用程序对资源操作,通常简单分为以下几个步骤:为对应的资源分配内存 → 初始化内存 → 使用资源 → 清理资源 → 释放内存. 2.应用程序对资源(内存使用)管理的方式,常见的一 ...

  8. 垃圾回收机制GC

    垃圾回收机制GC 我们已经知道,name = 'leethon'这一赋值变量的操作,是将变量与数据值相绑定. 而数据值是存储到内存中的,有时变量会重新赋值即绑定其他数据值,而使得原本的数据值无法通过变 ...

  9. 浅谈JVM垃圾回收

    JVM内存区域 要想搞懂啊垃圾回收机制,首先就要知道垃圾回收主要回收的是哪些数据,这些数据主要在哪一块区域. Java8和Java8之前的相同点有很多. 都有虚拟机栈,本地方法栈,程序计数器,这三个是 ...

随机推荐

  1. Spring整合Mybatis 之分页插件使用

    [分页插件项目中的正式代码一共有个5个Java文件,这5个文件的说明如下] Page<E>[必须]:分页参数类,该类继承ArrayList,虽然分页查询返回的结果实际类型是Page< ...

  2. cocos2dx 3.x 蒙板 遮罩 点击圆功能

    //注册触摸 EventListenerTouchOneByOne *listener = EventListenerTouchOneByOne::create(); listener->onT ...

  3. Python: 字符串格式化format()函数的使用

    python从2.6开始支持format,新的更加容易读懂的字符串格式化方法,从原来的% 模式变成新的可读性更强的 花括号声明{}.用于渲染前的参数引用声明, 花括号里可以用数字代表引用参数的序号, ...

  4. 搭建Mybatis 出现 Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mapper.BatchCustomer.findBatchCustomerOneToOne

    Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection doe ...

  5. springcloud9----feign-client-without-hystrix

    package com.itmuch.cloud; import org.springframework.boot.SpringApplication; import org.springframew ...

  6. 20162314 《Program Design & Data Structures》Learning Summary Of The Tenth Week

    20162314 2017-2018-1 <Program Design & Data Structures>Learning Summary Of The Tenth Week ...

  7. ubuntu16.04更新源的时候显示:由于没有公钥,无法验证下列签名: NO_PUBKEY 3D5919B448457EE0【学习笔记】

    平台:ubuntu16.04 作者:庄泽彬(欢迎转载,请注明作者) 在添加了bazel的源之后执行sudo apt-get update出现下面的错误 echo "deb [arch=amd ...

  8. P4 PI库安装

    repo:Github PI P4Runtime - a control plane framework and tools for the P4 programming language 这个是P4 ...

  9. Notepad++ 管理工程--转载

    http://blog.csdn.net/cashey1991/article/details/7001385 @1.首先从下面这个菜单打开工程panel @2.在工程panel的“Workspace ...

  10. QWebEngineView_CssVariables

    1.测试代码,参考网址:http://blog.sina.com.cn/s/blog_1508519340102wgq0.html 2.测试下来,结果: 2.1.Qt5.6开始,没有 WebKit了. ...