I've heard several people asking why GCHandle doesn't implement IDisposable, considering it wraps an unmanaged resource (a handle) and needs to be explicitly freed (using GCHandle.Free()). Before I explain the reason, I want to give a little background on GCHandles and their dangers.

What's a GCHandle?

A GCHandle is a struct that contains a handle to an object. It's mainly used for holding onto a managed object that gets passed to the unmanaged world to prevent the GC from collecting the object. You can also create a Pinned GCHandle to a managed object and retrieve the object's address in memory.

How are GCHandles dangerous?

When you create a new GCHandle, a new entry in the AppDomain's handle table is created. This entry is kept until the handle is freed (via GCHandle.Free()) or the AppDomain is unloaded.

Things get tricky if you were to make a copy of a GCHandle:

Object obj = new Object();
GCHandle gch = GCHandle.Alloc(obj, GCHandleType.Normal);
GCHandle gch2 = gch;

Since
GCHandle is value type, gch2 has its own copy of the handle. You now
have two handles that point to the same entry in the handle table.
Unfortunately, since gch2 is a copy of –not a reference to– gch,
anything that happens to gch doesn't happen to gch2. For example,
calling gch.Free() will delete the entry from the handle table, but not
update gch2, so gch2.IsAllocated will return true, but gch2.Target will
be null. The same problem arises with casting to and from IntPtrs, and
when GCHandles get boxed. Unlike double-freeing a single GCHandle,
freeing the copy will NOT throw an InvalidOperationException. You have
to be very careful not to double-Free your handles since this can
corrupt the handle table.

Why don't GCHandles implement IDisposable?

One
of the main purposes of IDisposable to avoid the use of finalizers.
This is because finalizers are not run deterministically, and result in
promoting a finalizable object a generation, effectively keeping in
memory longer. Since GCHandle is a value type, it has no finalizer, and
is not collected by the GC, so these problems are eliminated. Another
other main use of IDisposable is to clean up unmanaged resources as soon
as you are done with them. With a GCHandle, the resource is the handle
which is cleaned up by calling GCHandle.Free(). If Free isn't called,
the handle gets cleaned up when the appdomain is unloaded.

One
of the side effects of having a struct implement IDisposable, is that
users may be tempted to cast their GCHandles as IDisposable, which boxes
the GCHandle into an IDisposable object on the heap, and the two
GCHandles get out-of-sync. The same problem arises with the putting a
disposable struct into a using block:

struct Test : IDisposable
{
    public bool disposed; // initialized to false
    public void Dispose()
    {
        disposed = true;
    }
}

public void Foo()
{
    Test t = new Test();
    using (t)
    {
        // do stuff
    }

if (!t.disposed)
    {
        t.Dispose();
    }
}

t.disposed
will return false, since it was a copy of t whose Dispose method was
called. If t were a GCHandle, then the handle would be removed from the
appdomain's handle table, and calling Free after the using would result
in a double Free, even though IsAllocated would return true!

Remember,
GCHandles are advanced structures, and one should be very careful to
ensure they are cleaned up properly. Unfortunately, IDisposable makes it
easy to get this wrong, so the BCL designers erred on the side of
caution, and gave GCHandle a Free() method to use.

The Truth About GCHandles的更多相关文章

  1. hdu3729 I'm Telling the Truth (二分图的最大匹配)

    http://acm.hdu.edu.cn/showproblem.php?pid=3729 I'm Telling the Truth Time Limit: 2000/1000 MS (Java/ ...

  2. windbg 命令 gchandles

    使用windbg导出dump文件 .dump /ma D:\testdump.dmp gchandles命令列出句柄,同时列出句柄引用的对象,演示代码如下: using System; using S ...

  3. I'm Telling the Truth(二分图)

    .I'm Telling the Truth Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...

  4. 论文笔记之:Playing for Data: Ground Truth from Computer Games

    Playing for Data: Ground Truth from Computer Games ECCV 2016 Project Page:http://download.visinf.tu- ...

  5. codeforces Gym 100187L L. Ministry of Truth 水题

    L. Ministry of Truth Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100187/p ...

  6. Codeforces Gym 100610 Problem H. Horrible Truth 瞎搞

    Problem H. Horrible Truth Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/1006 ...

  7. 关于warning: suggest parentheses around assignment used as truth value [-Wparentheses]|的解决方法

    今天,在调试的时候一直出现warning: suggest parentheses around assignment used as truth value 代码如下: if(startTime== ...

  8. Pretty Smart? Why We Equate Beauty With Truth

    Pretty Smart? Why We Equate Beauty With Truth With some regularity we hear about the latest beauty-p ...

  9. [usaco]2013-jan Liars and Truth Tellers 真假奶牛

    Description 约翰有N头奶牛,有一部分奶牛是真话奶牛,它们只说真话,而剩下的是假话奶牛,只说假话.有一天,约翰从奶牛的闲谈中陆续得到了M句话,第i句话出自第Xi头奶牛,它会告诉约翰第Yi头是 ...

随机推荐

  1. input file 选择Excel文件 相关操作

    1.HTML代码 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebFo ...

  2. mysql系列之3.mysql进阶

    启动原理 mysqld脚本-->mysqld_safe脚本-->mysqld服务-->启动mysql 强制关闭mysql: 三种方法, 不建议用! killall mysqld pk ...

  3. JAVA中equals()与==的区别详解

    在进行判断操作时,常常会用到==或者equals()进行等价判断,那么两者究竟有什么区别呢,下面整理一下个人理解. 简单介绍: ==是一种引用相等性比较符,判断引用到堆上同一个对象的两个引用是相等的. ...

  4. ABAP 关键字(1)

    1.定义DATA ,TYPES TYPES关键字用于创建自定义数据类型,就像JAVA里面创建类一样,用TYPES创建的数据类型可以被其它变量引用(类似于实例化对象),而本身不能直接引用或者赋值. DA ...

  5. [IR课程笔记]Web search

    一.  搜索引擎 组成部分: 1. 网络爬虫(web crawler) 2. 索引系统(indexing system) 3. 搜索系统 (searching system) consideratio ...

  6. MySQL多表查询一网打尽

    现有四张表 mysql> select * from student; +------+--------+-------+-------+ | s_id | s_name | s_age | s ...

  7. php中一些比常见做法更好的实践

    有些被我们习以为常的做法未必就是最好的,它们可能存在一些安全问题,而解决这些隐患的成本,其实并不高: 密码 常见做法是直接MD5进行加密,比如这样: //加密 $passwordStr = md5($ ...

  8. BZOJ 4868-4873 题解

    BZOJ4868 每个结束位置的最优值很显然具有单调性,三分,再讨论一下就好了. #include<bits/stdc++.h> using namespace std; #define ...

  9. 《C prime plus (第五版)》 ---第11章 字符串和字符串函数---2

    11-3:字符串 输出 三个标准的函数:puts() fputs() printf() 1.puts()函数: #include<stdio.h> #define DEF "I ...

  10. .gitignore文件配置:keil工程文件类型【转】

    本文转载自:https://blog.csdn.net/u010160335/article/details/80043965 .gitignore源文件下载链接:git管理keil工程.gitign ...