- 1、本文档共5页,可阅读全部内容。
- 2、有哪些信誉好的足球投注网站(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
第
.net中如何以纯二进制的形式在内存中绘制一个对象
目录一、引用类型实例的内存布局二、以二进制的形式创建对象三、字节数组与实例状态的同一性四、ObjHeader针对哈希被同步状态的缓存一个对象总是映射一块连续的内存序列(不考虑对象之间的引用关系),如果我们知道了引用类型实例的内存布局,以及变量引用指向的确切的地址,我们不仅可以采用纯二进制的方式在内存绘制一个指定引用类型的实例,还可以修改某个变量的值指向它,还能直接通过改变二进制内容来更新实例的状态。
一、引用类型实例的内存布局
从内存布局的角度来看,一个引用类型的实例由如下图所示的三部分组成:ObjHeader+TypeHandle+Fields。前置的ObjHeader用来缓存哈希值和同步状态(《如何将一个实例的内存二进制内容读出来?》具有对此的详细介绍),TypeHandle部分存储类型对应方法表(MethodTable)的地址,方法表可以视为针对类型的描述。也正是这部分内容的存在,运行时可以确定任何一个实例的真实类型,所以我们才说引用类型的实例是自描述(SelfDescribing)的。Fields用于存储实例每个字段的内容。
对于32位(x86)的机器来说,ObjHeader和TypeHandle的长度都是4字节。如果是64位(x64)的机器,用于存储方法表地址的TypeHandle需要8个字节来存储,但是ObjHeader依然是4个直接。考虑到内存对齐,需要前置4个字节的Padding。对于一个不为null的应用类型变量来说,它存储的是实例的内存地址。但是这个地址并不是实例所在内存的首地址(ObjHeader),而是TypeHandle部分的地址。
二、以二进制的形式创建对象
既然我们已经知道了引用类型实例的内存布局,也知道了引用指向的确切的地址,我们不仅可以采用纯二进制的方式在内存绘制一个指定引用类型的实例,还可以修改某个变量的值指向它。具体的实现体现在如下所示的Create方法中,该方法根据指定的属性值创建一个Foobar对象。除了用来提供两个属性值的foo、bar参数之外,它还通过输出参数bytes返回整个实例的字节序列。
varfoobar=Create(1,2,outvarbytes);
Debug.Assert(foobar.Foo==1);
Debug.Assert(foobar.Bar==2);
staticunsafeFoobarCreate(intfoo,intbar,outbyte[]bytes)
Foobarfoobar=null!;
bytes=newbyte[24];
BinaryPrimitives.WriteInt64LittleEndian(bytes.AsSpan(8),typeof(Foobar).TypeHandle.Value.ToInt64());
BinaryPrimitives.WriteInt32LittleEndian(bytes.AsSpan(16),foo);
BinaryPrimitives.WriteInt32LittleEndian(bytes.AsSpan(20),bar);
Unsafe.Write(Unsafe.AsPointer(reffoobar),newIntPtr(Unsafe.AsPointer(refbytes[8])));
returnfoobar;
publicclassFoobar
publicintFoo{get;set;}
publicintBar{get;set;}
}
根据上述针对内存布局的介绍,我们知道任何一个Foobar实例在x64机器中都映射位一段连续的24字节内存,所以Create方法创建了一个长度位24的字节数组。我们保持ObjHeader为空,所以我们从第8(zerobased)个字节开始写入Foobar类型对应TypeHandle的值(8字节),然后将指定的数据成员的值(int类型占据4个字节)填充到最后8个字节(由于两个字段的类型均为int,所以不需要添加额外的留白来确保内存对齐)。自此我们将凭空在内存中绘制了一个Foobar对象。由于x86机器采用小端字节序,所以二进制的写入最终是通过调用BinaryPrimitives的WriteInt32/64LittleEndian方法来完成的。
接下来我们定义一个Foobar类型的变量,并让它指向这个绘制的Foobar对象
您可能关注的文档
最近下载
- 塔吊附墙计算书.pdf VIP
- 制造业企业质量管理能力评估规范团体标准.pdf VIP
- 11BS6通风与空调工程.docx VIP
- 2025《党政机关厉行节约反对浪费条例》PPT课件.pptx VIP
- 河南省南阳地区2023-2024学年高二下学期期末考试物理试卷(含答案).pdf VIP
- 自然资源局公务员考试行政能力测试能力测试卷.docx VIP
- 《我国本土酒店品牌建设问题及对策》.doc VIP
- 在线网课学习课堂《学术交流英语(哈工 )》单元测试考核答案.docx VIP
- JGT396-2012 外墙用非承重纤维增强水泥板.docx VIP
- 人人商城恶意诉讼应诉指南-含胜诉答辩状和证据清单.docx VIP
文档评论(0)