用long类型让我出了次生产事故,写代码还是要小心点

昨天发现线上试跑期的一个程序挂了,平时都跑的好好的,查了下日志是因为昨天运营跑了一家美妆top级淘品牌店,会员量近千万,一下子就把128G的内存给爆了,当时并行跑了二个任务,没辙先速写一段代码限流,后面再做进一步优化。

一:背景

1. 背景介绍

因为是自己写的代码,所以我知道问题出现在哪里,如果大家看过我之前写的文章应该知道我用全内存跑了很多模型对用户打标签,一个模型就是一组定向的筛选条件,而为了加速处理,我会原子化筛选条件,然后一边查询一边缓存原子化条件获取的人数,后面的模型如果命中了前面模型的原子化条件,那么可以直接从缓存中读取它的人数即可,这也是动态规划的思想~ ,如果不明白我来画张图。

从上面图可以看到,在计算模型2的时候,条件1的人数可以直接从模型1下的条件1处获取,模型三下的2,5的人数也可以直接从模型1和2处获取,这样就大大加速的处理速度。

2. 找原因

刚才提到了缓存人数,我也不知道为什么用了这么一个类型,如下代码:

        /// <summary>/// 缓存原子人群/// key: 原子化条件/// value: 人数集合/// </summary>public ConcurrentDictionary<string, List<long>> CachedCrowds { get; set; } = new ConcurrentDictionary<string, List<long>>();

我说的是里面的List\,我居然用了long类型存储customerID,可能是看了这个项目先祖原先定义的long才跟风成long,????????????,谁家店有数不尽的客户,国家才14亿人呢,而一个long占用8个字节,明显是一种浪费。

二:解决方案

1. 将long转成int

人都是懒的,能少改点代码就少改点,省的背锅,好事不出门,坏事传千里,所以这里用int表示就足够了,应该能省一半的空间对不对,接下来为了演示,在List\ 和 List\ 中分别灌入 500w 客户ID,代码如下:

public static void Main(string[] args){var rand = new Random();List<int> intCustomerIDList = Enumerable.Range(1, 5000000).OrderBy(m => rand.Next(0, 100000)).Take(5000000).ToList();List<long> longCustomerIDList = Enumerable.Range(1, 5000000).OrderBy(m => rand.Next(0, 100000)).Take(5000000).Select(m => (long)m).ToList();Console.WriteLine("处理完毕...");Console.Read();}

接下来用windbg看一下他们在堆中各占多少内存。

~0s -> !clrstack -l -> !dumpobj 从主线程找到List\和List\ 的局部变量,然后查看size。


0:000> ~0s
ntdll!ZwReadFile+0x14:
00007ff8`fea4aa64 c3              ret
0:000> !clrstack -l
OS Thread Id: 0x5b70 (0)Child SP               IP Call Site
00000015c37feed0 00007ff889e60b9c ConsoleApp2.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp2\Program.cs @ 35]LOCALS:0x00000015c37fef90 = 0x0000014ad7c12d880x00000015c37fef88 = 0x0000014ad7c130600x00000015c37fef80 = 0x0000014ad7c3343800000015c37ff1a8 00007ff8e9396c93 [GCFrame: 00000015c37ff1a8]
0:000> !do 0x0000014ad7c13060
Name:        System.Collections.Generic.List`1[[System.Int32, mscorlib]]
MethodTable: 00007ff8e7aaa068
EEClass:     00007ff8e7c0b008
Size:        40(0x28) bytes
File:        C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:MT    Field   Offset                 Type VT     Attr            Value Name
00007ff8e7a98538  400189e        8       System.Int32[]  0 instance 0000014af02d1020 _items
00007ff8e7a985a0  400189f       18         System.Int32  1 instance          5000000 _size
00007ff8e7a985a0  40018a0       1c         System.Int32  1 instance          5000000 _version
00007ff8e7a95dd8  40018a1       10        System.Object  0 instance 0000000000000000 _syncRoot
00007ff8e7a98538  40018a2        0       System.Int32[]  0   shared           static _emptyArray>> Domain:Value dynamic statics NYI 0000014ad61166c0:NotInit  <<
0:000> !do 0000014af02d1020
Name:        System.Int32[]
MethodTable: 00007ff8e7a98538
EEClass:     00007ff8e7c05918
Size:        33554456(0x2000018) bytes
Array:       Rank 1, Number of elements 8388608, Type Int32 (Print Array)
Fields:
None0:000> !do  0x0000014ad7c33438
Name:        System.Collections.Generic.List`1[[System.Int64, mscorlib]]
MethodTable: 00007ff8e7aad2a0
EEClass:     00007ff8e7c0bd70
Size:        40(0x28) bytes
File:        C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:MT    Field   Offset                 Type VT     Attr            Value Name
00007ff8e7aa6c08  400189e        8       System.Int64[]  0 instance 0000014a80001020 _items
00007ff8e7a985a0  400189f       18         System.Int32  1 instance          5000000 _size
00007ff8e7a985a0  40018a0       1c         System.Int32  1 instance          5000000 _version
00007ff8e7a95dd8  40018a1       10        System.Object  0 instance 0000000000000000 _syncRoot
00007ff8e7aa6c08  40018a2        0       System.Int64[]  0   shared           static _emptyArray>> Domain:Value dynamic statics NYI 0000014ad61166c0:NotInit  <<
0:000> !do 0000014a80001020
Name:        System.Int64[]
MethodTable: 00007ff8e7aa6c08
EEClass:     00007ff8e7c09e50
Size:        67108888(0x4000018) bytes
Array:       Rank 1, Number of elements 8388608, Type Int64 (Print Array)
Fields:
None

仔细看上图,在主线程的堆栈中找到了三个变量,后两个变量就是我们的List\ 和 List\,分别是

Size: 33554456(0x2000018) bytes => 33554456/1024/1024 = 32M

Size:67108888(0x4000018) bytes => 67108888/1024/1024 = 64M

以后可以跟别人吹牛了,我知道500w个int占用是32M内存,虽然内存空间优化了一半,但没有本质性的优化,还得继续往上挖,否则同时跑4个任务又要把内存给爆掉了。。。

2. 使用bitarray

我们在学习数据结构的时候,相信很多人都学习过bitmap,刚好原子化的筛选条件获取的人数众多,使用bitmap刚好满足我的业务需求,如果不知道bitmap我简单解释一下。

<1 style="box-sizing: border-box;"> 原理解释

我们都知道一个int是4个字节。也就是4byte,也就是32bit,画成图就是32个格子,如下所示:

默认情况下32个格子表示一个int是不是有点浪费,其实32个格子可以放置32个数字(1-32)。比如1放在第一个格子里,3放在第三个格子里。。。32放在第32个格子里,那么两个int就可以存放1-64个数字,也就是说理想情况下可以优化空间32倍,思维一定要反转一下,把数字作为数组的下标,因为是bit,所以0,1两种状态刚好可以表示当前格子是否已经被设置了,1表示已设置,0表示未设置,好好品味一下,如果还是不明白,可以参考我八年前的文章:

经典算法题每日演练——第十一题 Bitmap算法

在C#中已经帮我们设置好了一个BitArray类,结合我刚才讲得,大家好好品味一下bitarray如何向各自格子中设置值的,底层还是用m_array承载,它其实是一个int[]。


public void Set(int index, bool value){if (value){m_array[index / 32] |= 1 << index % 32;}else{m_array[index / 32] &= ~(1 << index % 32);}_version++;
}public bool Get(int index){return (m_array[index / 32] & (1 << index % 32)) != 0;
}

<2 style="box-sizing: border-box;"> 查看内存占用

接下来把List\ 中的数据灌入到bitArray中看看,先上一下代码:

public static void Main(string[] args){var rand = new Random();List<int> intCustomerIDList = Enumerable.Range(1, 5000000).OrderBy(m => rand.Next(0, 100000)).Take(5000000).ToList();BitArray bitArray = new BitArray(intCustomerIDList.Max() + 1);foreach (var customerID in intCustomerIDList){bitArray[customerID] = true;}Console.WriteLine("处理完毕...");Console.Read();}

然后抓一下dump文件,用windbg看一下内存占用。


0:000> !do 0x0000026e4d0332b8
Name:        System.Collections.BitArray
MethodTable: 00007ff8e7a89220
EEClass:     00007ff8e7c01bc0
Size:        40(0x28) bytes
File:        C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:MT    Field   Offset                 Type VT     Attr            Value Name
00007ff8e7a98538  4001810        8       System.Int32[]  0 instance 0000026e5dfd9bd8 m_array
00007ff8e7a985a0  4001811       18         System.Int32  1 instance          5000001 m_length
00007ff8e7a985a0  4001812       1c         System.Int32  1 instance          5000000 _version
00007ff8e7a95dd8  4001813       10        System.Object  0 instance 0000000000000000 _syncRoot
0:000> !DumpObj /d 0000026e5dfd9bd8
Name:        System.Int32[]
MethodTable: 00007ff8e7a98538
EEClass:     00007ff8e7c05918
Size:        625028(0x98984) bytes
Array:       Rank 1, Number of elements 156251, Type Int32 (Print Array)Fields:None

从图中可以看到,没错,就是bitArray类型,从Size中可以看到:

Size: 625028(0x98984) bytes => 625028/1024/1024 = 0.59M

看到没有,这个就????????了,由最初的64M优化到了0.6M,简直不要太爽,看到这么小的占用量,我感到枯燥而乏味,哈哈,这下并行跑几十家不怕了,这里要提醒一下,如果客户数少并且数字还大,就不要用bitArray啦,反而浪费空间,当然数据量小怎么用也无所谓。

三:总结

跑小店铺的时候代码怎么写都行,数据量大了到处都是坑,你的场景也总有优化的办法~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310301.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mongodb查询分析器解析

Mongodb查询分析器 动态相关项目中涉及到数据量大和吞吐量的接口&#xff0c;例如关注页面动态&#xff0c;附近动态&#xff0c;这部分数据都是存储在mongodb中&#xff0c;在线上数据中分类两个mongodb集合存储其中关注动态基于扩散写的设计&#xff0c;数据量已经快到 8 亿…

[Java基础]Collections概述和使用

代码如下: package CollectionDemo01;import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List;public class CollectionDemo01 {public static void main(String[] args){List<Integer> list new ArrayList&l…

链路追踪在ERP系统中的应用实践

源宝导读&#xff1a;随着ERP的部署架构越来越复杂&#xff0c;对运维监控、问题排查等工作增加了难度&#xff0c;本文将介绍通过引入链路追踪技术&#xff0c;提高ERP系统问题排查效率&#xff0c;支撑更全面监控系统运行情况的实践过程。一、导读随着ERP的部署架构越来越复杂…

[Java基础]File基础

File类概述和构造方法: 代码如下: package FileStudyPack;import java.io.File;public class FileDemo01 {public static void main(String[] args){File f1 new File("D:\\JavaDemo\\java.txt");System.out.println(f1);File f2 new File("D:\\JavaDemo&quo…

java 日志乱码_【开发者成长】JAVA 线上故障排查完整套路!

云栖号资讯&#xff1a;【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01;线上故障主要会包括 CPU、磁盘、内存以及网络问题&#xff0c;而大多数故障可能会包含不止一个层面的问题&#xff0c;所以进行…

谈谈登录密码传输这件小事

背景 大大小小的系统其实都离不开登录这个小小的功能&#xff0c;前段时间老黄在审查公司部分系统代码时&#xff0c;发现不少系统的登录还是很粗暴的&#xff0c;粗暴到让人不敢说话的那种。说到登录&#xff0c;结合标题&#xff0c;其实大部分人应该都猜到那个粗暴到让人不敢…

技术分享杂七杂八技术

技术分享 听花谷 距离名宿 6~7 公里左右&#xff0c;丽江网红基地&#xff0c;有举办婚礼的地方听花谷&#xff0c;坐落于玉龙雪山脚下&#xff0c;前有玉龙雪山&#xff0c;后有原始森林。园内共有三处白色空间&#xff0c;第一处共有三层&#xff0c;婚礼举行&#xff0c;发…

java 操作日志设计_日志系统新贵 Loki,确实比笨重的ELK轻

本文同步Java知音社区&#xff0c;专注于Java作者&#xff1a;linkt1234http://blog.csdn.net/Linkthaha/article/details/100575278最近&#xff0c;在对公司容器云的日志方案进行设计的时候&#xff0c;发现主流的ELK或者EFK比较重&#xff0c;再加上现阶段对于ES复杂的搜索功…

Istio1.5 Envoy 数据面 WASM 实践

Istio 1.5 回归单体架构&#xff0c;并抛却原有的 out-of-process 的数据面扩展方式&#xff0c;转而拥抱基于 WASM 的 in-proxy 扩展&#xff0c;以期获得更好的性能。本文基于网易杭州研究院轻舟云原生团队的调研与探索&#xff0c;介绍 WASM 的社区发展与实践。超简单版解释…

elasticSearch -- (文档,类型,索引)

问题:大规模数据如何检索 当系统数据量达到10亿&#xff0c;100亿级别的时候&#xff0c;我们系统该如何去解决这种问题。 数据库选择—mysql&#xff0c; sybase&#xff0c;oracle&#xff0c;mongodb&#xff0c;hbase…单点故障如何解决—lvs&#xff0c; F5&#xff0c;…

asp后台调用产品数据_后台产品经理,需掌握这些数据交互知识

人们每天都在接收信息和发送信息&#xff0c;在传递信息的过程中&#xff0c;明白对方要表达的意思。数据也是如此&#xff0c;在系统交换数据的过程中&#xff0c;就伴随着数据交互。本篇文章将为大家具体分析前端和后台的数据交互与协议。本文所说的”数据交换” 是指在计算机…

使用c# .net core开发国标gb28181 sip +流媒体服务完成视频监控实例教程 亲身完美体验过程...

目前使用C# .net core 来实现国标gb28181标准的摄像头播放、ptz云台控制、视频回放等视频监控功能&#xff0c;项目可运行于linux/docker/.net core环境&#xff0c;也是当前非常罕有的能做到毫秒级国标gb28181公网视频传送案例&#xff0c;也是少有的能同时具有播放、ptz云台控…

[Java基础]字节流读数据

代码如下: package InstreamPack;import java.io.FileInputStream; import java.io.IOException;public class FileInputStreamDemo01 {public static void main(String[] args) throws IOException {FileInputStream fis new FileInputStream("D:\\JavaDemo\\java.txt&…

丁可以组什么词_有哪些量词可以用来描述生意经?

分别有&#xff1a;本&#xff0c; 一(本)生意经。笔&#xff0c; 一(笔)生意经。次&#xff0c;一(次)生意量词用名量词&#xff1a;表示事物的计量单位。基本定义&#xff1a;通常用来表示人、事物或动作的数量单位的词&#xff0c;叫做量词。量词 lingc&#xff0c;与代表可…

硬核技能k8s初体验

&#xff0c;Kubernetes 是一个软件系统&#xff0c;使你在数以万计的电脑节点上运行软件时就像所有节点是以单个大节点一样&#xff0c; 它将底层基础设施抽象&#xff0c;这样做同时简化了应用开发、部署&#xff0c;以及对开发和运维团队的管理。Kubernetes集群架构Kubernet…

线上问题排查流程

问题排查 针对各种常见的线上问题&#xff0c;梳理下排查思路。 业务问题 线上问题大多数时候都是业务问题引发的问题&#xff0c;当线上环境绝大多数请求都是正常&#xff0c;当有部分或者某一个用户有问题&#xff0c;此时怎么针对性的排查在当前微服务体系下&#xff0c;…

springboot超详细教程_CG原画插画教程:超详细线稿教程

艺学绘小编收集整理了超详细线稿教程今天我们从起稿开始1. 用圆表示出人物的头部、胸腔和骨盆&#xff0c;分别画出头部的十字线和身体的中线&#xff0c;表示头和身体的朝向。用“火柴棍”表示四肢的动作形态。▼2. 根据圆和十字线画出脸的轮廓&#xff0c;再在身体骨架上画出…