设计背景
每个平台都会有用户这种基础数据的设计, 作为最基础的用户, 每个用户都有很多属性, 比如性别, 姓名, 手机号等, 每个用户还可以有类似经验值这样的荣誉系统, 根据不同的经验值来对应不同的等级, 不同的等级对应不同的荣誉 UI, 比如一级用户可能只显示一个星星, 二级用户显示两颗星星, 以此类推, 类似于 QQ 等级的星星月亮太阳, 这样的荣誉系统随着平台的不断壮大, 可能会衍生出很多类型. 那么问题来了, 用户登录的时候就需要初始化用户的这些荣誉值, 以星星数为例, 类似于以下代码
- public class Star
- {
- // 等级
- public int Level{get ;set ;}
- // 对应的星星数目
- public int StarNumber{get ;set ;}
- // 对应的星星颜色
- public int Color{get ;set ;}
... 其他属性
- }
- // 用户信息
- public class User{
- public Star StarInfo{get ;set ;}
- //... 用户的其他属性
- }
- // 初始化用户信息
- User u=new User(){ StarInfo=new Star(){ Level=1, StarNumber=1,Color=1}};
每一个登录用户都会初始化一个 Star 属性来表示当前用户的 Star 信息, 当有 100 万用户甚至更多用户同时在线的时候, 内存中就实例化了同样数量的 Star 对象, 以及其他类似的属性对象. 这么多重复的对象难道不能优化吗? 当然不是!!
问题分析
一个业务出现问题, 首先要分析问题的所在. 根据以上所说, 问题的根本在于产生了大量的对象, 首先每个用户对象都有自己独特的状态, 这个基本上不可能分解优化, 但是类似 Star 这样的属性就有优化途径了, 这些荣誉属性一个最大的共同点就是不可变, 换句话说, 等级 1 的用户对应的 Star 信息是永远不会变的, 永远是 level=1,starnumber=1,color=1 等. 基于这个不变性, 我们可以把这个 Star 抽离出来, 供所有等级 1 的用户使用, 假设原来有 10 万等级 1 的用户, 原来需要 10 万个对象, 现在只需要一个对象, 这可是天壤之别.
解决问题
基于以上问题分析, 我们需要做的是把对象重复使用, 只要是对象重复问题, 基本上可以利用一个对象出口来解决问题, 类似于以下的对象初始化工厂, 但是要注意线程安全问题, 因为同时请求并初始化对象的线程会有多个.
- public class UserStarFac
- {
- static object objLock = new object();
- static Dictionary<int, Star> UserStarMap = new Dictionary<int, Star>();
- public static Star GetUserStar(int level)
- {
- // 利用锁来防止实例化多次, 当然这里可以优化
- lock (objLock)
- {
- Star info = null; ;
- if(!UserStarMap.TryGetValue(level, out info))
- {
- info = new Star() { Color = 1, Level = 1, StarNumber = 1 };
- UserStarMap.Add(level,info);
- }
- return info;
- }
- }
- }
编写简单测试程序
- static void Main(string[] args)
- {
- int i = 0;
- List<User> userList = new List<User>();
- while (i < 100000)
- {
- // userList.Add(new User() { StarInfo=new Star() { Color=1, Level=1, StarNumber=1} });
- userList.Add(new User() { StarInfo= UserStarFac .GetUserStar(1)});
- i++;
- }
- Console.WriteLine("初始化完成");
- Console.Read();
- }
内存的测试结果:
不执行任何程序: 占用内存: 2.8 M
无优化初始化 10 万对象: 占用内存: 11 M
优化之后初始化 10 万对象: 占用内存: 7 M
居然一个小小的优化就减少了 4M 内存, 不要小看这小小的 4M, 你要看的是比例, 居然减少了将近 50%, 真实业务中, 可以进行这种优化的地方数不胜数, 不知道你是否在乎呢?
这种大量重复对象的问题尤其是在游戏编程中经常存在, 比如五子棋游戏, 棋子的初始化, 一个游戏大厅存在成千上百万对局, 如果每个局中的棋子都初始化一个对象, 那内存使用是相当可怕的, 这种需要把通用的对象属性, 不变的对象属性抽离出来, 做共享是有必要的.
据说这种优化有一个学名: 享元模式, 没有必要记住名字, 但需要记住原理和场景, 必须要提一句: 注意不变的对象才可以哦
来源: https://www.cnblogs.com/zhanlang/p/12550179.html