The Truth About GCHandles
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的更多相关文章
- 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/ ...
- windbg 命令 gchandles
使用windbg导出dump文件 .dump /ma D:\testdump.dmp gchandles命令列出句柄,同时列出句柄引用的对象,演示代码如下: using System; using S ...
- I'm Telling the Truth(二分图)
.I'm Telling the Truth Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- 论文笔记之:Playing for Data: Ground Truth from Computer Games
Playing for Data: Ground Truth from Computer Games ECCV 2016 Project Page:http://download.visinf.tu- ...
- 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 ...
- Codeforces Gym 100610 Problem H. Horrible Truth 瞎搞
Problem H. Horrible Truth Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/1006 ...
- 关于warning: suggest parentheses around assignment used as truth value [-Wparentheses]|的解决方法
今天,在调试的时候一直出现warning: suggest parentheses around assignment used as truth value 代码如下: if(startTime== ...
- 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 ...
- [usaco]2013-jan Liars and Truth Tellers 真假奶牛
Description 约翰有N头奶牛,有一部分奶牛是真话奶牛,它们只说真话,而剩下的是假话奶牛,只说假话.有一天,约翰从奶牛的闲谈中陆续得到了M句话,第i句话出自第Xi头奶牛,它会告诉约翰第Yi头是 ...
随机推荐
- HttpClient 访问 https 出现peer can't
package util; import java.security.cert.CertificateException; import javax.net.ssl.SSLContext;import ...
- 【题解】[P3557 POI2013]GRA-Tower Defense Game
[题解][P3557 POI2013]GRA-Tower Defense Game 这道题是真的** 根据题目给的\(k\),可以知道,我们随便放塔,只要不全放一起,一定是一种合法的方案. 直接枚举就 ...
- 我的Android进阶之旅------>Android通过使用Matrix旋转图片来模拟碟片加载过程
今天实现了一个模拟碟片加载过程的小demo,在此展示一下.由于在公司,不好截取动态图片,因此就在这截取两张静态图片看看效果先. 下面简单的将代码列出来. setp1.准备两张用于旋转的图片,如下:lo ...
- Flask:程序结构
在Flask中需要配置各种各样的参数.比如设置秘钥,比如上一章介绍到的配置数据库类型. app.config['SECRET_KEY']=os.urandom(20) app.config['SQLA ...
- Pentaho BIServer Community Edtion 6.1 使用教程 第四篇 安装和使用Saiku 插件 进行 OLAP
OLAP(On-Line Analytical Processing,联机分析处理)是一个使分析师.管理者和执行者从原始数据中用来快速.一致.交互访问的一种软件技术,从而真实的反映企业的数据情况.OL ...
- PR 批量导入
REPORT ZMM_UPLOAD_PR. DATA: BEGIN OF GT_DATA1 OCCURS 0, BSART TYPE STRING, "凭证类型 ...
- Android适配API23之后权限的动态申请
一.权限介绍 对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装,造成了我们想要使用某个app,就要默默忍受其一些不必要的权限(比如是个app都要 ...
- Machine Learning No.7: Support Vector Machines
1. SVM hypothsis 2. large margin classification 3. kernals and similarity if f1 = 1; if x if far fr ...
- NPM 与 Nodejs
安装了Nodejs之后,NPM也安装好了 如何知道当前是否已经安装Nodejs和NPM了呢? node -v //查看当前nodejs的版本 npm -v //查看当前npm的版本 NPM 初始化 n ...
- event loop笔记
注意四个对象: 主进程 执行栈 异步进程 任务队列 1.主进程读取js代码,形成对应的堆和执行栈(此时在同步环境) 2.当遇见异步任务,转交给异步进程进行处理 3.异步任务完成,将其推入任务队列 4. ...