博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.net core中的高效动态内存管理方案
阅读量:6008 次
发布时间:2019-06-20

本文共 2572 字,大约阅读时间需要 8 分钟。

.net core在新增的System.Buffers中引入了一大堆高效内存管理的类,如、。本文今天这里介绍一个高效动态内存访问方案。

 

ReadOnlySequenceSegment<T>

在我们读取数据的过程,很多时候会出现如下场景:

  1. 不知道数据实际大小
  2. 一次性申请大量内存开销太大

此时我们往往会使用动态内存的方案,通过链表的方式串联起来,从而形成逻辑意义上的数据流。如下图所示:

ReadOnlySequenceSegment<T>就是这样一个表示数据流节点的内存模型,它是一个抽象类,包含如下三个元素:

  • Memory        指向所包含的内存
  • Next        指向下一个节点
  • RunningIndex        标志当前节点在整个流的位置

其中Memory和Next还比较容易理解,典型的链表结构。主要难理解的是RunningIndex,他表示该节点在数据流中的Memory起始索引。

一般的来讲,某节点的RunningIndex为其上一个节点的RunningIndex + Memory.Length。加上RunningIndex估计主要是为了快速索引的。

例如:对于如下3快内存 100byte, 200byte, 300byte组成的链表,其RunningIndex分别是0, 100, 200。

另外,在实际的使用过程中,往往是不停的释放链表头部的节点,并且在尾部添加新节点。 RunningIndex表示的索引一般是逻辑意义上的索引,在释放头节点时,一般不用更新其子节点以及后续节点的RunningIndex。

 

ReadOnlySequence<T>

ReadOnlySequenceSegment<T>虽然能解决我们的动态内存的申请和释放问题,但它往往并不好用,因为很容易出现一段连续的数据被分割在多个节点的情况,在这段不连续的数据里进行查询是非常不便的。

为了解决这个问题,.net core中推出了一个视图类ReadOnlySequence<T>

ReadOnlySequence<T>由两个属性标记:

  • Start: 起始SequenceSegment以及起始索引
  • End: 结尾SequenceSegment以及结尾索引

可以通过foreach遍历各节点的Memory

  var seq = new ReadOnlySequence
();   foreach (ReadOnlyMemory
memory in seq)   {   }

ReadOnlySequence的主要优势在于,它可以看成一段逻辑意义上的连续内存,常用的函数有:

  • Slice: 对视图数据切片
  • PositionOf: 查询元素的缩影
  • ToArray: 转换成数组

其中的ToArray涉及到大量的数据拷贝,需要谨慎使用。

另外.net core 3.0中还内置了一个SequenceReader,用起来是十分方便的: 

private static ReadOnlySpan
CRLF => new byte[] { (byte)'\r', (byte)'\n' }; public static void ReadLines(ReadOnlySequence
sequence){ SequenceReader
reader = new SequenceReader
(sequence); while (!reader.End) { if (!reader.TryReadToAny(out ReadOnlySpan
line, CRLF, advancePastDelimiter: false)) { // Couldn't find another delimiter // ... } if (!reader.IsNext(CRLF, advancePast: true)) { // Not a good CR/LF pair // ... } // line is valid, process ProcessLine(line); }}
View Code

 

如何使用

用过的朋友就知道,ReadOnlySequence在该库中是非常好用的。但如果我们想常见一个ReadOnlySequence,发现并不是那么容易,因为:

  1. ReadOnlySequence依赖于ReadOnlySequenceSegment
  2. ReadOnlySequenceSegment是抽象类,需要自己继承

也就是说我们需要自己实现ReadOnlySequenceSegment<T>,然后再将其封装到ReadOnlySequence中,目前.net core中并没有内置实现可能是因为在高效内存管理的方案中并没有什么通用的解决方案吧。

如果我们要自己实现ReadOnlySequence,一般需要如下几个步骤:

  1. 继承ReadOnlySequenceSegment类,实现自己的SequenceSegment
  2. 在申请内存过程中,创建SequenceSegment,并将其挂成链表
  3. 使用数据时,在该链表中创建ReadOnlySequence
  4. 当SequenceSegment节点的内存使用完成的时候,从链表中接触该节点,并释放内存。

简单来说就是如下几种操作:

  • 数据读取: 创建SequenceSegment
  • 数据使用: 在SequenceSegment链表上创建ReadOnlySequence
  • 使用完成: 释放SequenceSegment

如果要更进一步优化,在SequenceSegment中的内存申请和释放可以使用内存池。

转载地址:http://ursmx.baihongyu.com/

你可能感兴趣的文章
移动互联网,入口生死战
查看>>
nginx面试常问题目
查看>>
制作ubuntu系统u盘镜像,以及安装
查看>>
JAVA多线程深度解析
查看>>
Kafka High Level Consumer 会丢失消息
查看>>
时间轴
查看>>
入坑vim之配置文件vimrc
查看>>
java 获取系统当前时间的方法
查看>>
Ubuntu 10.04升级git 到1.7.2或更高的可行方法
查看>>
MyBATIS(即iBATIS)问题集
查看>>
Linux下autoconf和automake使用
查看>>
UDP之socket编程
查看>>
Spring Security4实战与原理分析视频课程( 扩展+自定义)
查看>>
Centos6.5升级系统自带gcc4.4.7到gcc4.8.0
查看>>
redis安装与配置文件详解
查看>>
VMware安装失败 “Failed to create the requested registry key Key:installer Error:1021"
查看>>
虚拟化系列-VMware vSphere 5.1 VDP备份管理
查看>>
接口设计
查看>>
同步工具类 java.util.concurrent.CountDownLatch
查看>>
带动量因子的BP网络源码(C#实现)
查看>>