【微软技术栈】使用新的C#功能减少内存分配
本文内容
- 通过引用传递和返回
- 引用安全上下文
- 安全的上下文和 ref 结构
- 统一内存类型
- 通过参考安全提高性能
本节中介绍的技术可提高应用于代码中的热路径时的性能。热路径是代码库中在正常操作中经常重复执行的部分。将这些技术应用于不经常执行的代码将产生最小的影响。在进行任何更改以提高性能之前,测量基线至关重要。然后,分析该基线以确定内存瓶颈发生的位置。
测量内存使用情况并确定可以减少分配后,请使用本节中的技术来减少分配。每次连续更改后,再次测量内存使用情况。确保每个更改都会对应用程序中的内存使用产生积极影响。
.NET 中的性能工作通常意味着从代码中删除分配。您分配的每个内存块最终都必须被释放。较少的分配可减少垃圾回收所花费的时间。它通过从特定代码路径中删除垃圾回收,允许更可预测的执行时间。
减少分配的常用策略是将关键数据结构从类型更改为类型。此更改会影响使用这些类型的语义。参数和返回现在按值传递,而不是按引用传递。如果类型很小,只有三个字或更少(考虑到一个字的自然大小为一个整数),则复制值的成本可以忽略不计。它是可衡量的,可以对较大的类型产生真正的性能影响。为了消除复制的影响,开发人员可以传递这些类型来获取预期的语义。
使用 C# 功能,您可以表达所需的类型语义,而不会对其整体可用性产生负面影响。在实现这些增强功能之前,开发人员需要求助于具有指针和原始内存的构造,以实现相同的性能影响。编译器为新的相关功能生成可验证的安全代码。可验证的安全代码意味着编译器检测到可能的缓冲区溢出或访问未分配或释放的内存。编译器会检测并防止某些错误。
1、通过引用传递和返回
C# 中的变量存储值。在类型中,该值是该类型的实例的内容。在类型中,该值是对存储该类型实例的内存块的引用。添加修饰符意味着变量存储对值的引用。在类型中,引用指向包含该值的存储。在类型中,引用指向包含对内存块的引用的存储。
在 C# 中,方法的参数是按值传递的,返回值是按值返回的。参数的值将传递给该方法。返回参数的值是返回值。
或 修饰符指示参数是通过引用传递的。对存储位置的引用将传递给该方法。添加到方法签名意味着通过引用返回返回值。对存储位置的引用是返回值。
您还可以使用 ref 赋值让一个变量引用另一个变量。典型的赋值将右侧的值复制到赋值左侧的变量。ref 赋值将右侧变量的内存位置复制到左侧的变量。现在指的是原始变量:
int anInteger = 42; // assignment.
ref int location = ref anInteger; // ref assignment.
ref int sameLocation = ref location; // ref assignmentConsole.WriteLine(location); // output: 42sameLocation = 19; // assignmentConsole.WriteLine(anInteger); // output: 19
分配变量时,会更改其值。当您 ref 赋值一个变量时,您可以更改它所引用的内容。
您可以使用变量、通过引用传递和引用赋值直接处理值的存储。编译器强制执行的范围规则可确保直接使用存储时的安全性。
和修饰符都指示参数应通过引用传递,并且不能在方法中重新赋值。区别在于,该方法将参数用作变量。该方法可能会捕获参数,也可能通过只读引用返回参数。在这些情况下,应使用修饰符。否则,修饰符将提供更大的灵活性。您无需将修饰符添加到参数的参数中,因此您可以使用修饰符安全地更新现有 API 签名。如果未将 or 修饰符添加到参数的参数中,编译器将发出警告。
2、引用安全上下文
C# 包含表达式规则,以确保在表达式引用的存储不再有效的情况下无法访问表达式。请看以下示例:
public ref int CantEscape()
{int index = 42;return ref index; // Error: index's ref safe context is the body of CantEscape
}
编译器报告错误,因为无法从方法返回对局部变量的引用。调用方无法访问所引用的存储。ref 安全上下文定义表达式可以安全访问或修改的范围。下表列出了变量类型的 ref 安全上下文。 字段不能在 a 或 non-ref 中声明,因此这些行不在表中:
| 声明 | ref 安全上下文 |
|---|---|
| 非 ref 本地 | 声明 local 的块 |
| non-ref 参数 | current 方法 |
ref参数ref readonlyin | 调用方法 |
out参数 | current 方法 |
class田 | 调用方法 |
non-ref 字段struct | current 方法 |
ref领域ref struct | 调用方法 |
如果变量的 ref 安全上下文是调用方法,则可以返回该变量。如果其 ref 安全上下文是当前方法或块,则不允许返回。以下代码片段显示了两个示例。可以从调用方法的作用域访问成员字段,因此类或结构字段的 ref 安全上下文是调用方法。带有 或修饰符的参数的 ref 安全上下文是整个方法。两者都可以从成员方法返回:
private int anIndex;public ref int RetrieveIndexRef()
{return ref anIndex;
}public ref int RefMin(ref int left, ref int right)
{if (left < right)return ref left;elsereturn ref right;
}
编译器确保引用无法转义其引用安全上下文。您可以安全地使用参数、 和局部变量,因为编译器会检测您是否意外编写了代码,在表达式存储无效时可以访问表达式。
3、安全的上下文和 ref 结构
ref struct类型需要更多的规则来确保它们可以安全使用。类型可以包含字段。这需要引入一个安全的环境。对于大多数类型,安全上下文是调用方法。换言之,始终可以从方法返回不是 ref structrefref struct的值。
非正式地,a 的安全上下文是可以访问其所有字段的范围。换句话说,它是其所有字段的 ref 安全上下文的交集。以下方法返回 a to a member 字段,因此其安全上下文是该方法:ref structrefrefReadOnlySpan<char>
private string longMessage = "This is a long message";public ReadOnlySpan<char> Safe()
{var span = longMessage.AsSpan();return span;
}
相反,以下代码会发出错误,因为 的成员引用了堆栈分配的整数数组。它无法转义方法:ref fieldSpan<int>
public Span<int> M()
{int length = 3;Span<int> numbers = stackalloc int[length];for (var i = 0; i < length; i++){numbers[i] = i;}return numbers; // Error! numbers can't escape this method.
}
4、统一内存类型
System.Span<T> 和 System.Memory<T> 的引入为使用内存提供了统一的模型。System.ReadOnlySpan<T> 和 System.ReadOnlyMemory<T> 提供用于访问内存的只读版本。它们都提供了对存储类似元素数组的内存块的抽象。区别在于 和 是类型,而 和 是类型。跨度包含一个 .因此,跨度的实例不能离开其安全上下文。a 的安全上下文是其 的 ref 安全上下文。实施并删除此限制。您可以使用这些类型直接访问内存缓冲区。Span<T>ReadOnlySpan<T>ref structMemory<T>ReadOnlyMemory<T>structref fieldref structref fieldMemory<T>ReadOnlyMemory<T>
5、通过参考安全提高性能
使用这些功能提高性能涉及以下任务:
- 避免分配:将类型从 a 更改为 时,会更改其存储方式。局部变量存储在堆栈上。分配容器对象时,成员以内联方式存储。此更改意味着分配更少,从而减少了垃圾回收器所做的工作。它还可能会降低内存压力,从而降低垃圾回收器的运行频率。
- 保留引用语义:将类型从 a 更改为 a 会更改将变量传递给方法的语义。修改其参数状态的代码需要修改。现在参数是 ,该方法正在修改原始对象的副本。您可以通过将该参数作为参数传递来还原原始语义。更改后,该方法将再次修改原始内容。
- 避免复制数据:复制较大的类型可能会影响某些代码路径的性能。还可以添加修饰符,以便通过引用而不是按值将较大的数据结构传递给方法。
- 限制修改:当通过引用传递类型时,被调用的方法可以修改结构的状态。您可以将修饰符替换为 or 修饰符,以指示无法修改参数。当方法捕获参数或通过只读引用返回参数时,首选。还可以创建类型或具有成员的类型,以便更好地控制可以修改的成员。
- 直接操作内存:当将数据结构视为包含一系列元素的内存块时,某些算法最有效。和类型提供对内存块的安全访问。
这些技术都不需要代码。如果使用得当,您可以从安全代码中获得性能特征,而以前只能使用不安全技术才能实现。
相关文章:
【微软技术栈】使用新的C#功能减少内存分配
本文内容 通过引用传递和返回引用安全上下文安全的上下文和 ref 结构统一内存类型通过参考安全提高性能 本节中介绍的技术可提高应用于代码中的热路径时的性能。热路径是代码库中在正常操作中经常重复执行的部分。将这些技术应用于不经常执行的代码将产生最小的影响。在进行任何…...
Linux shell编程学习笔记29:shell自带的 脚本调试 选项
Linux shell脚本的调试方法比较多,上次我们探讨和测试了shell内建命令set所提供的一些调试选项,其实 shell 本身也提供了一些调试选项。我们以bash为例来看看。 1 bash 的命令行帮助信息(bash --help) purleEndurer csdn ~ $ ba…...
分享几个可以免费使用GPT的网站
ChatGPT这个是国产的,里面可以使用3.5和4.0,免费用户每日都有各自的使用次数,反应迅速。文言一心国内百度的chart8新用户200次,但只能用3.5,响应速度有点慢 各有优缺点,大家看个人情况使用,个人…...
一. BEV感知算法介绍
目录 前言1. BEV感知算法的概念2. BEV感知算法数据形式3. BEV开源数据集介绍3.1 KITTI数据集3.2 nuScenes数据集 4. BEV感知方法分类4.1 纯点云方案4.2 纯视觉方案4.3 多模态方案 5. BEV感知算法的优劣6. BEV感知算法的应用介绍7. 课程框架介绍与配置总结下载链接参考 前言 自动…...
Scala如何写一个通用的游戏数据爬虫程序
以前想要获取一些网站数据的时候,都是通过人工手动复制粘贴,这样的效率及其低下。数据少无所谓,如果需要采集大量数据,手动就显得乏力了。半夜睡不着,爬起来写一段有关游戏商品数据的爬虫通用模板,希望能帮…...
前端命名规范总结
布局类:header, footer, container, main, content, aside, page, section 包裹类:wrap, inner 区块类:region, block, box 结构类:hd, bd, ft, top, bottom, left, right, middle, col, row, grid, span 列表类:list,…...
Vue学习笔记-搭建Vuex
1.概念 在Vue实现集中式状态(数据)管理的一个插件,对Vue中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通信方式,适用于任意组件间的通信 2.使用场景 多个组件需要共享数据时…...
Ajax技
Ajax的特点 异步提交:Ajax采用异步通信方式,能够在页面无需重新加载的情况下向服务器发送请求并接收响应数据,提升了用户体验。无需插件:Ajax是基于标准浏览器的Javascript和XMLHttpRequest对象实现的,无需安装插件或…...
Co-DETR:DETRs与协同混合分配训练论文学习笔记
论文地址:https://arxiv.org/pdf/2211.12860.pdf 代码地址: GitHub - Sense-X/Co-DETR: [ICCV 2023] DETRs with Collaborative Hybrid Assignments Training 摘要 作者提出了一种新的协同混合任务训练方案,即Co-DETR,以从多种标…...
ELk部署,保姆级教学超详细!!!
Elk(Elasticsearch, Logstash, Kibana)是一套日志收集、存储和展示方案,是由Elastic公司开发的开源软件组合。 Elasticsearch:是一个分布式的搜索和分析引擎。它能够处理大量的数据,并提供快速、准确的搜索结果&#x…...
计算机毕业设计springboot+vue高校田径运动会报名管理系统61s38
高校田径运动会管理采用java技术,基于springboot框架,mysql数据库进行开发,实现了首页、个人中心、运动员管理、裁判员管理、场地信息管理、项目类型管理、比赛项目管理、比赛报名管理、比赛成绩管理、通知公告管理、留言板管理、交流论坛、系…...
java学习part21枚举
117-面向对象(高级)-枚举类的两种定义方式及练习_哔哩哔哩_bilibili 1.概念 2.enum关键字 枚举早期是用class内放n个public static final类变量供调用。 后来有了enum关键字,enum里的枚举变量都是public static final,但是必须都省略不写 正确方法 &…...
MongoDB的部署
MongoDB部署 基于Linux平台 前置要求 在Centos7 64位系统中安装64位的MongoDB的安装包,通过访问MongoDB官网https://www.mongodb.com/download-center/community进入MongoDB下载页面。Version:指定MongoDB版本,MongoDB的版本分为稳定版和开发…...
解析和存储优化的批量爬虫采集策略
如果你正在进行批量爬虫采集工作,并且想要优化解析和存储过程,提高采集效率和稳定性,那么本文将为你介绍一些实用的策略和技巧。解析和存储是批量爬虫采集中不可忽视的重要环节,其效率和质量对整个采集系统的性能至关重要。在下面…...
【git】使用ssh
前言 git之前一直使用https,因为很方便随时随地都可以用。最近把代码托管到GitHub,使用https就使用不了。后面听同事说GitHub使用ssh是没问题的,就想着尝试一下。 git ssh配置 设置用户名和邮箱 git config --global use.name username g…...
Linux 文件锁
1 为什么用文件锁 文件是一种共享资源,多个进程对同一文件进行操作的时候,必然涉及到竞争状态,因此引入了文件锁实现对共享资源的访问进行保护的机制,通过对文件上锁, 来避免访问共享资源产生竞争状态。 2 文件锁用法 (1)参考文档: man 2 …...
原理Redis-SkipList
SkipList ZipList和QuickList的共同特点是节省内存。在遍历元素时,只能从头到尾或从尾到头,所以在查找头尾元素性能还是不错的,但是中间元素查询的性能就会差。 **SkipList(跳表)**首先是链表,但与传统链表…...
Express内置的中间件
自Express 4.16.0 版本开始,Express 内置了3个常用的中间件,极大的提高了 Express 项目的开发效率和体验: 1.express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等 (无兼容性) 2.express.json 解析JSON 格式的请…...
Webstorm 插件文件目录颜色分析——白蓝绿红黄灰
Webstorm 插件文件目录【白色、蓝色、绿色、红色、黄色、灰色】对应当前文件发生什么了,即文件夹当前状态。 WebStrom配置好git或SVN后文件颜色代表的含义: 白色:本地无修改内容 蓝色:文件内容有修改,暂未提交到git…...
蓝桥杯day01——根据给定数字划分数组
题目描述 给你一个下标从 0 开始的整数数组 nums 和一个整数 pivot 。请你将 nums 重新排列,使得以下条件均成立: 所有小于 pivot 的元素都出现在所有大于 pivot 的元素 之前 。所有等于 pivot 的元素都出现在小于和大于 pivot 的元素 中间 。小于 piv…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...
倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
高效的后台管理系统——可进行二次开发
随着互联网技术的迅猛发展,企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心,成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统,它不仅支持跨平台应用,还能提供丰富…...
