10 月 23 - 25 日,QCon 上海站即将召开,现在购票,享9折优惠 了解详情
写点什么

C#的未来:托管指针

  • 2015-05-05
  • 本文字数:1388 字

    阅读完需:约 5 分钟

对于许多开发者,尤其是编写游戏软件,以及进行纯数字计算的开发者来说,原始性能是程序的重中之重。同时对他们来说,最大的问题莫过于内存分配了。虽然分配操作本身消耗很小,但过多的分配会造成内存的极大压力,并且造成垃圾回收器的执行周期更加频繁。

在堆中分配的内存也会造成缓存的问题。如果你有一个存放引用类型的列表或是数组,它的实际数据与数组本身是分开进行保存的。这意味着你可能不得不浪费更多的缓存线以保存这个数组以及由数组所引用的对象。而如果我们在同一时间内创建了这些对象,那么可能会造成很大的分散性,进而导致消耗更多的缓存线。相关数据的分散性也就导致了糟糕的局部性(locality)。

使用值类型(在 C#的说法中也就是结构体)能够极大地减少内存的分配次数并改善局部性。但是,在结构体的使用上存在着一些限制。因为设计它们的初衷是传递拷贝,因此你必须保证它们的尺寸非常小,否则就很可能受到性能上的严惩,这也违背了在第一时间使用值类型的本意。

为了避免无意义的拷贝,一种做法是在将值类型传递给函数时使用一个托管指针。目前为止,唯一一种能够在 C#中创建托管指针的做法是在参数前使用“ref”关键字。这种做法确实能够应对某些场景的性能问题,但实际上 CLR 通过托管指针能够实现的功能远不止这些。

Ref 返回值与 Ref 本地变量这条提议中,提出了另外两种能够为 C#程序员所用的选项。

Ref 本地变量

假设有一个 int 类型的本地变量 a,这条提议允许你通过以下语法创建一个 Ref 本地变量:

ref int x = a;

类似于 ref 参数,ref 本地变量本质上就是它所指代的本地变量的某个别名而已,这种方式使你不必再生成它的拷贝。你也可以通过这种语法创建一个指向某个数组元素、或指向另一个对象的某个字段的指针。

ref int y = b[2];
ref int z = c.d;

在 CLR 术语中,Ref 本地变量被称为一个“TypedReference”(类型化引用)。一个 TypedReference 包含了指向某个地址的指针,同时也包含了该地址所能够存放的数据的类型信息。

按规定,一个 TypedReference 必须是一个参数或本地变量。这一规定是因为 CLR 不允许堆中的元素指向其它元素的内部。你也无法返回一个 TypedReference 对象,否则你就可以返回一个对本地对象的引用,而这个对象在函数结束后自然是已经不存在了。

Ref 返回值

这条提议的第二部分允许你在函数中返回 ref 引用,这就使以下场景变得可能:

public static ref TValue Choose(
Func condition, ref TValue left, ref TValue right)
{
return condition() ? ref left : ref right;
}
Matrix3D left = […], right = […];
Choose(chooser, ref left, ref right).M20 = 1.0;

通过使用这种新语法,以上的示例代码就不会对结构体进行任何拷贝操作,而是创建托管指针并在方法调用中进行传递。

与 ref 本地变量不同,要实现这一特性或许必须对 CLR 标准进行改动。正如之前所说,通常来说是不允许返回 TypedReference 对象的。从技术上讲你可以这么做,但这种操作不是类型安全的,其结果也是“无法检验的”。在受限安全设置中,使用未经检验的代码是不允许的,因为它可能会引起严重的 bug,因此一般只在 C 与 C++ 中使用。

为了缓解这一风险,这条提议中也表示,你所返回的引用必须指向堆中的某个对象,或是指向某个已经存在的 ref 或 out 参数。换句话说,编译器将强迫你不能够返回某个指向本地变量的引用。

查看英文原文: C# Futures: Managed Pointers

2015-05-05 09:573244
用户头像

发布了 428 篇内容, 共 194.7 次阅读, 收获喜欢 39 次。

关注

评论

发布
暂无评论
发现更多内容

Java中多线程安全问题实例分析

叫练

Java 多线程 什么是多线程 多线程与高并发

第13周作业

饭桶

如何在数智化时代少走弯路? 这里有100个案例可以借鉴

京东科技开发者

DevOps 云原生

图文回顾丨北京「解构云原生:企业数字化转型新支点」沙龙

Rancher

k8s rancher

Apache顶级项目ShardingSphere — SQL Parser的设计与实现

京东数科风险算法与技术

数据库 开源 中间件

大咖直播 | Elasticsearch 应用监控管理平台搭建实战

腾讯云大数据

大数据 elasticsearch Elastic Stack 监控管理平台

即构实时音视频多中心调度设计

ZEGO即构

传统巨头抢占区块链场景高地 医疗、汽车、金融成为热门赛道

CECBC

区块链 金融

告别消费主义的双12,是华为云12.12会员节真正的意义

脑极体

这才是你需要的C/C++Linux学习路线!

赖猫

c++ Linux 后台开发 服务器开发

EMAS远程日志 - 移动端问题排查利器

移动研发平台EMAS

阿里云 运维 日志 监控告警 应用

Shell脚本命令常用技巧

MySQL从删库到跑路

shell脚本编写

自建本地电话告警系统

周楠

运维 物联网 监控告警

互联网应用系统常见问题与方案

raox

极客大学架构师训练营

牵头成立“现代计算联盟”,强大如谷歌也需要组团打怪吗?

脑极体

面向全场景模块化设计 京东智联云的服务器部署有多灵活?

京东科技开发者

服务器 云主机

住建部等六部门:广泛运用区块链等技术,建设智慧物业管理服务平台

CECBC

物业生活

浅谈JDK并发包下面的分治思想及分治思想在高并发场景的运用

AI乔治

Java 架构 jdk 分布式 多线程与高并发

建信金科大咖访谈:金融衍生品定价与建行实践

金科优源汇

金融科技 金融创新

AWS 助力贝壳VR看房走出国门,升级全球居住服务新体验

亚马逊云科技 (Amazon Web Services)

AWS

云原生架构-可观测性之 Prometheus 服务自动发现

云原生实验室

太赞了!滴滴开源了一套分布式ID的生成系统...

Java架构师迁哥

搭建网站/APP最全准备攻略

前嗅大数据

小程序 建站 APP发布

第十三周学习总结

饭桶

信任的传递——为什么我们需要第三方授权?

张凯峰

证书 身份认证

记一次MapReduce的内存溢出

AI乔治

Java mapreduce 架构 内存溢出

云南区块链电子发票全面推广啦!

CECBC

区块链 纳税人

附PPT丨AI和云原生时代的数据库进化之路

dbaplus社群

数据库 云原生

Elasticsearch 新机型发布,性能提升30%

腾讯云大数据

大数据 elasticsearch Elastic Stack

静态代码分析工具评估指标及方法

maijun

几种常见的研发管理体系,哪种更适合你?

菜根老谭

敏捷开发 研发管理 CMMI IPD

C#的未来:托管指针_.NET_Jonathan Allen_InfoQ精选文章