慎用ToLower和ToUpper,小心把你的系统给拖垮了
不知道何时开始,很多程序员喜欢用ToLower,ToUpper去实现忽略大小写模式的字符串相等性比较,有可能这个习惯是从别的语言引进的,大胆猜测下是JS,为了不引起争论,我指的JS是技师的意思~
一:背景
1. 讲故事
在我们一个订单聚合系统中,每一笔订单都会标注来源,比如JD,Taobao,Etao,Shopex 等等一些渠道,UI上也提供高级配置输入自定义的订单来源,后来客户反馈输入xxx查询不出订单,这里就拿shopex为例,用户用小写的shopex查询,但系统中标注的是首字母大写的Shopex,所以自然无法匹配,为了解决这个问题开发小哥就统一转成大写做比对,用代码表示如下:
var orderfrom = "shopex".ToUpper();
customerIDList = MemoryOrders.Where(i =>i.OrderFrom.ToUpper()==orderFrom)
.Select(i => i.CustomerId).ToList();
改完后就是这么牛的上线了,乍一看也没啥问题,结果一查询明显感觉比之前速度慢了好几秒,干脆多点几下,好咯。。。在监控中发现CPU和memory突高突低,异常波动,这位小哥又在写bug了,查了下代码问他为什么这么写,小哥说在js中就是这么比较的~~~
2. string.Compare 改造
其实在C#中面对忽略大小写形式的比较是有专门的方法,性能高而且还不费内存,它就是 string.Compare,所以把上面代码改成如下就可以了。
var orderfrom = "shopex";
customerIDList = MemoryOrders.Where(string.Compare(i.TradeFrom, tradefrom,
StringComparison.OrdinalIgnoreCase) == 0)
.Select(i => i.CustomerId).ToList();
这其中的 StringComparison.OrdinalIgnoreCase枚举就是用来忽略大小写的,上线之后除了CPU还是有点波动,其他都没有问题了。
二:为什么ToLower,ToUpper会有如此大的影响
为了方便演示,我找了一篇英文小短文,然后通过查询某一个单词来演示ToUpper为啥对cpu和memory以及查询性能都有如此大的影响,代码如下:
public static void Main(string[] args)
{
var strList = "Hooray! It's snowing! It's time to make a snowman.James runs out. He makes a big pile of snow. He puts a big snowball on top. He adds a scarf and a hat. He adds an orange for the nose. He adds coal for the eyes and buttons.In the evening, James opens the door. What does he see? The snowman is moving! James invites him in. The snowman has never been inside a house. He says hello to the cat. He plays with paper towels.A moment later, the snowman takes James's hand and goes out.They go up, up, up into the air! They are flying! What a wonderful night!The next morning, James jumps out of bed. He runs to the door.He wants to thank the snowman. But he's gone.".Split(' ');
var query = "snowman".ToUpper();
for (int i = 0; i < strList.Length; i++)
{
var str = strList[i].ToUpper();
if (str == query)
Console.WriteLine(str);
}
Console.ReadLine();
}
1. 内存波动探究
既然内存有波动,说明内存里进了脏东西,学C#基础知识的时候应该知道string是不可变的,一旦有修改就会生成新的string,那就是说ToUpper之后会出现新的string,为了用数据佐证,用windbg演示一下。
0:000> !dumpheap -type System.String -stat
Statistics:
MT Count TotalSize Class Name
00007ff8e7a9a120 1 24 System.Collections.Generic.GenericEqualityComparer`1[[System.String, mscorlib]]
00007ff8e7a99e98 1 80 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Globalization.CultureData, mscorlib]]
00007ff8e7a9a378 1 96 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Globalization.CultureData, mscorlib]][]
00007ff8e7a93200 19 2264 System.String[]
00007ff8e7a959c0 429 17894 System.String
Total 451 object
可以看到托管堆上有Count=429个string对象,那这个429怎么来的? 组成:短文128个,ToUpper后128个,系统默认165个,query字符串2个,不明字符串6个,最后就是128 +128 + 165 + 2 + 6=429,然后随便抽几个看看。
!dumpheap -mt 00007ff8e7a959c0 > !DumpObj 000002244282a1f8
0:000> !DumpObj /d 0000017800008010
Name: System.String
MethodTable: 00007ff8e7a959c0
EEClass: 00007ff8e7a72ec0
Size: 38(0x26) bytes
File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: HOUSE.
Fields:
MT Field Offset Type VT Attr Value Name
00007ff8e7a985a0 4000281 8 System.Int32 1 instance 6 m_stringLength
00007ff8e7a96838 4000282 c System.Char 1 instance 48 m_firstChar
00007ff8e7a959c0 4000286 d8 System.String 0 shared static Empty
>> Domain:Value 0000017878943bb0:NotInit <<
0:000> !DumpObj /d 0000017800008248
Name: System.String
MethodTable: 00007ff8e7a959c0
EEClass: 00007ff8e7a72ec0
Size: 40(0x28) bytes
File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: SNOWMAN
Fields:
MT Field Offset Type VT Attr Value Name
00007ff8e7a985a0 4000281 8 System.Int32 1 instance 7 m_stringLength
00007ff8e7a96838 4000282 c System.Char 1 instance 53 m_firstChar
00007ff8e7a959c0 4000286 d8 System.String 0 shared static Empty
>> Domain:Value 0000017878943bb0:NotInit <<
查了两个全是大写的“HOUSE”,“SNOWMAN”,再回到我的场景有小百万订单,也就会在托管堆上生成小百万个string,如果再点一次又会生成小百万个,内存怎么会不突增呢。。。
2.cpu和查询时间探究
现在大家知道了堆上可能有几百万个string对象,这些对象的分配和释放给cpu造成了不小的压力,本身toUpper之后速度变慢,更惨的是还会造成gc颤抖式触发,一颤抖所有的thread都会被暂停开启回收,速度就更慢了。。。
三:string.Compare解析
再回过头来看一下string.Compare为什么这么
慎用ToLower和ToUpper,小心把你的系统给拖垮了的更多相关文章
- 不小心改了Xcode系统的头文件,运行报错,解决办法
- Shell脚本编程的常识
(这些往往是经常用到,但是各种网络上的材料都语焉不详的东西,个人认为比较有用) 七种文件类型 d 目录 ...
- shell脚本编程常识
(这些往往是经常用到,但是各种网络上的材料都语焉不详的东西,个人认为比较有用) 七种文件类型 d 目录 ...
- R语言中的字符串处理函数
内容概览 尽管R是一门以数值向量和矩阵为核心的统计语言,但字符串有时候也会在数据分析中占到相当大的份量. R语言是一个擅长处理数据的语言,但是也不可避免的需要处理一些字符串(文本数据).如何高 ...
- SHELL脚本编程的常识和VI常用技巧
来源:http://mprc.pku.edu.cn/mentors/training/TrainingCourses/material/ShellProgramming.HTM#_Toc3751808 ...
- C primer plus 5 读书笔记2
1..字符串的输入:scanf()在读入时,当遇到空白字符空格blank.制表符tab.换行符newline时停止读取.一般使用gets(),来输入字符串. 2.strlen(),一字符为单位输出输出 ...
- C 标准库系列之ctype.h
ctype.h 主要提供了一些函数用以测试字符或字符处理的功能函数:包括字符判断检测.字符转换: 目前ASCII字符可分为以下一些类型,如:大写.小写.字母.数字.十六进制.空白字符.可打印字符.控制 ...
- POCO库——Foundation组件之核心Core
核心Core: Version.h:版本控制信息,宏POCO_VERSION,值格式采用0xAABBCCDD,分别代表主版本.次版本.补丁版本.预发布版本: Poco.h:简单地包含了头文件Found ...
- 02-C#入门(枚举、结构等)
不要为了写笔记而学习!!! 其实学完一章再返回复习,然后做笔记,真的很费时间(电子书还不方便).当然,复习带来的价值,是值得花时间的. 枚举.结构 枚举的类型有限(short.byte...)且是相同 ...
随机推荐
- Alibaba Cloud Linux 2 LTS 正式发布,提供更高性能和更多保障!
在Alibaba Cloud Linux 2(原Aliyun Linux 2)上线一年之际阿里云对外正式发布Alibaba Cloud Linux 2 LTS版本.LTS版本的发布对于Alibaba ...
- 刨根问底系列(2)——stdin、stdout、FILE结构体、缓冲区和fflush的理解
stdin.stdout.FILE结构体.缓冲区和fflush理解 因为之前调试代码时, printf输出的字符串总是被截断了输出(先输出部分, 再输出剩余的), 当时调试了很久, 才知道问题所在, ...
- Linux学习6-安装Python3.6
前言 今天我们来学习一下如何在Linux环境下安装Python3.6吧! 一:下载Python3.6(我下载的是python3.6.8) 地址:https://www.python.org/downl ...
- D3平移和缩放后的点击坐标(D3 click coordinates after pan and zoom)
我使用D3库来创建绘图应用程序. 我需要在用户单击的坐标上绘制对象(为了简单起见).问题是当用户使用平移&缩放和移动视口.然后对象是错误的位置的地方(我想问题是事件坐标是相对于svg元素而不是 ...
- 手把手教Extjs-简单GridField示例讲解二
使用的Extjs版本为4.2,示例是官方的版本,对里面的语法进行一句一句的学习研究.可以方便他人,又可以提升自己的理解.里面存在的问题,后期会一步一步改进.也欢迎各位指出. /* Extjs具有很庞大 ...
- Daily Scrum 1/11/2016
Zhaoyang & Minlong: Took and edited the video which introduced our APP. Yandong: Summarized bugs ...
- 1327C - Game with Chips (构造)
题目大意:一个n*m的棋盘上有k个棋子,k个棋子相互关联,可以一起向上向下向左向右,当碰到边界时,如果继续移动会发生越界,那么该棋子会保持不动,其余棋子继续移动.问能否在2*n*m的移动次数内,使各个 ...
- 谁说 Vim 不好用?送你一个五彩斑斓的编辑器!
相信大家在使用各种各样强大的 IDE 写代码时都会注意到,代码中各种类型的关键字会用独特的颜色标记出来,然后形成一套语法高亮规则.这样不仅美观,而且方便代码的阅读. 而在上古神器 Vim 中,我们通常 ...
- spark 集群优化
只有满怀自信的人,能在任何地方都怀有自信,沉浸在生活中,并认识自己的意志. 前言 最近公司有一个生产的小集群,专门用于运行spark作业.但是偶尔会因为nn或dn压力过大而导致作业checkpoint ...
- ADO.NET(二)
对Command的拓展延伸 执行SQL语句. Command 对象需要取得将要执行的SQL语句,通过调用该类的多种方法,向数据库提交SQL语句. ExecuteNonQuery(),ExecuteR ...