字符串内存优化

news/2024/11/7 13:45:28/

【前言】

字符串占用的内存往往很多,优化的空间很大,在做内存优化的时候,优化字符串内存是必不可少的一步。

字符串内存优化的核心原则有三个:

1.复用字符串,减少字符串数量

2.降低不可复用字符串的占用的内存

3.降低运行时产生的GC字符串内存

在这个三个核心原则下又有一些具体的方法。

【复用字符串,减少字符串数量】

出现大量重复字符串有两种情况:一是在不同的地方写了很多字符串,这可能是因为同一个人不同时间写的忘了之前的,不同的人写的互相不知道,不同地方调用无法传递等等原因;二是在字符串拼接的过程中一些字符被反复使用。

解决方法如下:

1.驻留池

CLR对string内存配分做了特殊处理,内部维护了一个驻留池的东西。其内部实质是维护了一个字典,key是字符串,value就是分配在堆上的字符串引用地址。如果发现字典中存在该字符串时,返回value中的地址,而不是给该字符串分配内存后再返回地址。什么时候CLR会使用这个字典呢?

  • 利用字面量值创建string对象(字面量在编译阶段有确定的值,能够发现很多相同的string)
  • 利用string.Intern()创建string对象(这允许我们在运行时主动将某个字符串放入驻留池中,缺点是当我我们已经不需要使用这个字符串时,其仍存在与驻留池中占用一部分内存)
  • 字面量值+字面量值拼接创建string对象

2.自己创建类似驻留池的字典

随着项目越来越复杂,CLR的驻留池总有不够用的时候,需要自己创建一个类似驻留池的字符串字典来实现字符串复用。

3.避免在不同地方读取同一份涉及字符串的文本或资源等,尽量保证这一份资源在内存中只存在一份。

【降低不可复用字符串的占用的内存】

不可以复用的字符串主要是因为其和资源绑定在一块或者说本身就是资源的一部分,是需要在运行时读取到程序内的,为了降低这些字符串的内存,必须简化字符串的长度。

我们利用字符串其实是为了表示一种情况或者一种东西,不同情况或不同东西的字符串唯一,可以保证字符串和情况一一对应即可。

在此之前,需要了解下字符串的组成:(以32bit为例)

1.作为引用类型,不可缺少的部分:引用头(object header)需要8 bytes(包含4bytes 同步索引块和4bytes的类型对象指针)

2.一个int32的字段,记录字符串的长度(在字符串的各种操作中,求长度的速度是最快的,直接查询就好。这也限制了一个字符串的最大长度)

3.结尾的空字符占用两个字节

4.剩下的部分是存放于字符缓冲区的字符内容,以空字符结尾

因此,一个字符串占用的内存大小为   14(8+4+2)+2*字符数。例如对于“HelloWorld"字符串,其所占用的内存大小为34 字节。注意,在C#中对string 类型采用UTF-16编码,所以string类型中一个字符占2个字节。

注意,这只是字符串所需要的内存大小,因为.NET的GC采用32位内存对齐(即所有的分配的内存都是4字节的整数倍),所以”HelloWorld"实际所占用的内存大小是36字节。

(一个空字串string.Empty占用8字节)

解决方法如下:

1.在保持字符串意思的前提下,尝试简化字符串,例如Chinese用CN代替等等

2.有的字符串不能简化,例如路径,这时可以对字符串做Hash,保证每个字符串对应唯一的hash值即可

3.在字符串有限的情况下,用byte、uint等类型代替字符串,并建立一张映射表。例如字符串种类不超过8种,用byte类型等

4.用byte[]代替string

5.通过对业务进行分析,有些字符串并不会同时出现,可以按需加载

通过这5种方法,字符串所占用内存通常可以优化80%以上。

【降低运行时产生的GC字符串内存】

1.一个是平时写代码时要注意可能产生字符串GC的情况,尤其是在高频的地方更要注意

2.有些地方实在是避免不了产生GC,例如Number To String的操作,这时可以单独开辟一块常驻内存,进行字符串操作时都在这块内存中进行操作,不断复用这块内存,这可以避免产生GC,这也是0GC string方案的原理。一般来说,用zstring的方案就足够了,项目地址如下:GitHub - 871041532/zstring: C# string零GC补充方案

【字符串性能相关的操作】

1.创建空字符串用用string s = string.Empty,而不是string s = ""

2.高频字符串拼接用stringbuilder

3.ToUpper、ToLower这类方法均会重新生成字符串,看看是否可以避免使用

4.true判断时,用"value" == string是最快的;false判断时,用"value".Equals(string)是最快的

5.字符串比较操作


http://www.ppmy.cn/news/31686.html

相关文章

ESP32设备驱动-红外寻迹传感器驱动

红外寻迹传感器驱动 1、红外寻迹传感器介绍 红外寻迹传感器具有一对红外线发射管与接收管,发射管发射出一定频率的红外线,当检测方向遇到障碍物(反射面)时,红外线反射回来被接收管接收,经过比较器电路处理之后,输出接口会输出一个数字信号(低电平或高电平,取决于电路…

若依框架部署从零开始2023版(前后端分离)

前言电脑最近重装了一次系统,目前什么都没有安装,记录一下从零开始部署前后端分离版本的若依框架系统先去官网把若依源码拉下来代码克隆若依目前已经有很多的版本了,因为现在开发比较流行前后端分离,因此这里演示前后端分离版本点…

【算法】算法基础入门详解:轻松理解和运用基础算法

😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!&#x1f4…

MatCap模拟光照效果实现

大家好,我是阿赵 之前介绍过各种光照模型的实现方法。那些光照模型的实现虽然有算法上的不同,但基本上都是灯光方向和法线方向的计算得出的明暗结果。 下面介绍一种叫做MatCap的模拟光照效果,这种方式计算非常简单,脱离灯光的计算…

有关3dmax对齐技巧的那些事

建模操作中,对齐是非常常用的一个功能,用好这个对齐功能能够事半功倍,好处我不说了,下面我们这篇博文就来说说3dmax对齐技巧的相关的内容。 文章目录一、点对齐1、样条线中的点对齐2、多边形中的点对齐二、线对齐三、面对齐四、物…

【C++】你不得不爱的——继承

凡是面向对象的语言,都有三大特性,继承,封装和多态,但并不是只有这三个特性,是因为者三个特性是最重要的特性,那今天我们一起来看继承! 目录 1.继承的概念及定义 1.概念 2.继承的定义 2.基类…

论文笔记 | 标准误聚类问题

关于标准误的选择,如是否选择稳健性标准误、是否采取聚类标准误。之前一直是困惑的,惯用的做法是类似主题的文献做法。所以这一次,借计量经济学课程之故,较深入学习了标准误的选择问题。 在开始之前推荐一个知乎博主。他阅读了很…

SQL注入进阶练习(一)一些进阶的注入方法

SQL注入进阶练习1. 二次注入1.1 概念1.2 sqllabs less-241.2.1 利用示例1.2.2 原理剖析1.3 网鼎杯2018 二次注入1.3.1 环境搭建1.3.2 解题思路1.3.2.1 寻找源码 - git泄露数据恢复1.git是啥2.获取源码泄露的数据1.3.2.2 源码分析1.3.2.3 爆破登陆密码1.3.2.4 实施二次注入获取f…