怎么快速初始化一个49W的数组
代码如下:
publc class TCellinfo
{
public byte chFlag;
public List<object> ObjList;
}
下面是我现在写的代码,但是这样占用内存太高了,求高手给出高效率的方法。
public TCellinfo[] CellArray;
public TCellinfo CellInfo;
CellArray= new TCellinfo[700*700];//或者更大的数字
for (int nW = 0; nW < m_nWidth; nW++)
{
for (int nH = 0; nH < m_nHeight; nH++)
{
CellInfo= new TCellinfo();
CellArray[nW * m_nHeight + nH] = CellInfo;
}
}
我想关键不在这几句代码。。。你看下有没有必要必须初始化这么大的数组。
不过初始化49W长度的数组应该不会慢,看你这也没放什么东西进去,也不会占用多少内存啊。
必须初始化这么大的数组。
现在分配内存之后,然后加载文件,内存狂飙到800M。。实在让人受不了
@茶语咖啡:
里面都放了什么,这么大。。。你这800M的内容时刻都要用到吗?应该不会吧,可以稍微转换下思路。
@向往-SONG:
几百个文件
时刻都需要用到
是你加载文件到内存里来,当然内存狂飙,分批加载,没办法。我一般用linq 初始化
var CellArray1 = Enumerable.Repeat<TCellinfo>(new TCellinfo(), 700 * 7000).ToArray();
这跟数组没关系,49w的数组占不了多少内存,关键你这个数组里存的都是文件,文件吃内存。我看你说几百个文件,时刻都用到,怎么可能呢?你任何时刻,都要同时用这几百个文件?这种情况肯定无法做到都加在到内存中的,等需要用到文件的时候再去读文件,才是正确的做法。
这是一个游戏场景服务器。。时刻都在检查玩家在地图上的动作。。。
@茶语咖啡: 那800m对于服务器来说也没什么啊,咋就吃不消了呢
@水牛刀刀: 就是想优化这段代码。。。
@茶语咖啡: 那你的玩家的动作应该用事件抛出来呀,遍历什么的效率总会有瓶颈啊
@梦 境: 这段代码只需要初始化一次,玩家的地图动作是根据玩家所在地图坐标+范围来判断事件的...只是这里一直new TCellinfo();--这里确实有点消耗内存..
@茶语咖啡: new TCellinfo() 光这句只耗了几个byte的内存。
for (int nH = 0; nH < m_nHeight; nH++)
{
CellInfo= new TCellinfo();
把这遍历 换成 获得行数据数组,然后看看有没有addRange这样的操作,也许速度会快一点~
如果是这样的话,这里还是一样会new TCellinfo();--43W次.
昨天我把TCellinfo改成结构体,内存明显下降很多.
@茶语咖啡: 我是指 CellInfo[] cis = CellHelper.Factory.GetArray();
去掉一层遍历
@茶语咖啡: 再就是,试试并行
@茶语咖啡:
数据并行(任务并行库)
http://msdn.microsoft.com/zh-cn/library/dd537608
试试unsafe代码呢?直接用指针进行操作,文件根本不用全放到内存,不要忘记还有个文件内存映射的WIN32 API可用。
看这个连接:
http://www.soaspx.com/dotnet/csharp/csharp_20120605_9244.html
.Net 4.0中引入了System.IO.MemoryMappedFiles
你可以构建一个锯齿数组,你两个for循环在一起肯定很慢,如下是解决方案:
1 public class TCellinfo 2 { 3 public byte chFlag; 4 5 public List<object> ObjList; 6 7 public override string ToString() 8 { 9 return "a"; 10 } 11 } 12 13 class Program 14 { 15 /// <summary> 16 /// 返回一个length*length的锯齿数组 17 /// </summary> 18 public static TCellinfo[][] CreateArray(int length) 19 { 20 TCellinfo[][] jarray = new TCellinfo[length][]; 21 TCellinfo[] array = new TCellinfo[length]; 22 23 for (int i = 0; i < length; i++) 24 { 25 array[i] = new TCellinfo(); 26 } 27 28 for (int i = 0; i < length; i++) 29 { 30 jarray[i] = array; 31 } 32 return jarray; 33 } 34 35 /// <summary> 36 /// 遍历锯齿数组 37 /// </summary> 38 public static void IterateArray(TCellinfo[][] tcs) 39 { 40 for (int i = 0; i < tcs.Length; i++) 41 { 42 Console.Write((i + 1).ToString() + " "); 43 44 for (int j = 0; j < tcs[i].Length; j++) 45 { 46 Console.Write("{0,8}", tcs[i][j].ToString()); 47 } 48 Console.WriteLine(); 49 } 50 } 51 52 static void Main(string[] args) 53 { 54 Console.WriteLine("{0,4} {1,8} {2,8} {3,8} {4,8} {5,8}", "Num", "1", "2", "3", "4", "5"); 55 IterateArray(CreateArray(5)); 56 } 57 }
下面是运行结果:
Num 1 2 3 4 5
1 a a a a a
2 a a a a a
3 a a a a a
4 a a a a a
5 a a a a a
(1)如果你确实确实需要把这么多信息同时放在内存里,那你的服务器就应该有这个性能的支撑能力。
(2)你应该转换思路,用可接受的时间成本来节省内存。
(3)你确定700*700这么多个元素每个元素里都包含有内容的链表吗?他们中有多少比例链表是空的?如果是这样,你这样大量分配对象是不太合理的。你可以把700*700个杂乱的小链表拼合成一个链表。这样就可以避免大量分配小对象。
(4)如果你对内存和效率有很高很精确的要求,请重新考虑你选择.net是否合适。
服务器性能绝对够了,我的目的是看能不能优化下这个方法,对于服务器来说800M内存并不算什么。
700*700是根据游戏地图宽高计算出来的。。
@茶语咖啡: 如果你只是对着这几行代码发呆,内心里根本不愿意或想不到去改变思路,转变观念,那又谈何优化呢。
既然需要这样的大的操作,那你就应该首先想到的是提高内存。
改变为结构体后, 整体内存的使用情况下降是必须的,因为结构体不包含组成class的那个8 bytes.
另外,就像楼上说的,我认为你没必要一次性开那么大的数组~这是需求问题,不是技术问题.
不要分配这么多小对象,CLR对对象处理的开销很大。
你可以分配大块内容,然后自己管理,比如: byte[] chFlag = new byte[700*700],
链表也可以这么处理,但要复杂一些