节约内存的小技巧——数据打包
说实话,技巧太小。
现在,你的任务是设计一个《大富翁》。地图上有50块地,我们不妨定义一个Field类。它应该有哪些数据成员呢?一个可能的设计是:
int x_player; //人的占位
int y_player;
int x_house; //房子的占位
int y_house;
int price; //地价
int houseType; //建筑物
int owner; //所有者 0表示空地
int state; //状态
就这样吧,也许不合适,但这只是个例子,每一块地需要32个字节。
然后我们来看,如果整张地图的大小是250*250,那么一个坐标就没有必要用4个字节,1个足够;我们可以进行第一步改进:
byte x_player;
byte y_player;
byte x_house;
byte y_house;
int price;
byte houseType;
byte owner;
byte state;
一共占用11个字节。
接着,考虑到房子相对于人的方位只有4种(左上、左下、右上、右下),而且只要方位相同,坐标差就相同,这样只要2位足以保存房子的坐标;
考虑到地价不会超过999999(最贵的商业街,最顶级的房子,而且地价临时上涨的情况),那么price需要20位;
建筑物只有3级,需要2位;
npc人物有6个,owner需要3位;
state无非正常、地价上涨、地价下跌、被查封4种情况,需要2位。
于是新的设计如下:
//保存4种情况下,房子和角色的坐标差
static final byte[] instance=new byte[]{dx1,dy1,dx2,dy2,dx3,dy3,dx4,dy4};
byte x_player;
byte y_player;
int otherValue;//在这32位中,housePosition占2位,houseType占2位,npcId占3
//位,state占2位,price占20位,剩余3位,你还可以定义其他属性
一共占用6个字节。
你可以联合使用逻辑操作和移位操作存取你打包的数据。
当然缺点也是不言而喻的,实际上并不总是这样精打细算,但总会有需要精打细算的时候。
这里只有50片地,如果是2000支股票,50000个客户信息呢?
问题点数:0、回复次数:12Top
1 楼midamia(戒骄戒躁,不忘本色)回复于 2003-12-03 00:06:10 得分 0
抛砖引玉,希望大家都来介绍介绍自己的心得Top
2 楼mercuryking(时间空间)回复于 2003-12-03 08:21:48 得分 0
很强!Top
3 楼ludingping(http://blog.csdn.net/ludingping)回复于 2003-12-03 08:33:02 得分 0
很好。让我认识到凡事只要有心,就可以做到精益求精Top
4 楼sunny110(沙漠)回复于 2003-12-03 09:01:17 得分 0
学习Top
5 楼huowenfeng(痛苦来源于对小概率事件的不懈追求)回复于 2003-12-03 09:07:08 得分 0
pretty boy.Top
6 楼AOM(spaces.msn.com/aom7610)回复于 2003-12-03 10:21:26 得分 0
有搞头!
Top
7 楼jax(阿杰)回复于 2003-12-03 10:35:05 得分 0
真的不错,不过这里还是有必要同时考虑运行的速度和编程效率问题Top
8 楼midamia(戒骄戒躁,不忘本色)回复于 2003-12-03 10:41:37 得分 0
昨天太晚,没有写晚,下面的部分更精彩。
对于50片地,通常的做法是:
class GameFullCanvas extends FullCanvas{
private Field[] fields = new Field[50];//当然,还需要对每一个成员初始化
//以下略
}
但我们知道,每一个对象都要占用额外的内存空间(如一些指向函数的指针),大量的数据应该使用基本数组,而不是对象数组来维护。同时,数据在打包的情况下读写很麻烦,给维护和测试带来很多不便。
这种情况,有的人会放弃对象思想,完全使用数组,把java当c语言来用。就像这样:
class GameFullCanvas extends FullCanvas{
static final byte[] instance = new byte[]{dx1,dy1,dx2,dy2,dx3,dy3,dx4,dy4};
static final byte[] x_player;
static final byte[] y_player;
staitc int[] otherValue;
//以下略
}
这样一来Field类就没有存在的必要了,原本Field类中的方法都可以放在GameFullCanvas里,并且以j2me游戏设计是面向屏幕的,而不是面向对象的为其理论基础。而且这并没有解决打包数据读取不变的问题。
在传统面向对象思想不可用的情况下,如何变通是摆在我们每一个j2me程序员面前的课题。
我的解决方案如下:
class Field{
static final byte[] instance = new byte[]{dx1,dy1,dx2,dy2,dx3,dy3,dx4,dy4};
static final byte[] x_player;//需初始化,以下同
static final byte[] y_player;
static int[] otherValue;
//都定义成int也无妨了,就奢侈一点吧
private int fieldId;
private int x_Player;
private int y_Player;
private int x_House;
private int y_House;
private int price;
private int houseType;
private int npcId;
private int state;
public init(int id){
fieldId = id;
x_Player = x_player[id];
y_Player = y_player[id];
//所有打包数据解包,并保存在相应变量中
//可能还有其他初始化代码
}
public pack(){
//在这里所有成员变量打包,保存进静态数组
}
//省略其他方法
}
如何使用这个Field类呢?请看:
class GameFullCanvas extends FullCanvas{
private Field field = new Field();
private someFunction(){
field.init(fieldId);
field.someFunction();
//如果数据发生改变,就打包保存,也可以由field自己决定是否保存
field.pack();
}
//以下略
}
这样,虽然地有50片,但是Field类的实例只有一个,并且被反复重用。不知这个技巧是编码的技巧,还是设计的技巧?
最后,希望我的文章对大家有帮助。Top
9 楼jigsaw(echo)回复于 2003-12-03 11:11:08 得分 0
en...楼主很强,佩服。
我就是抛不掉以前的思路,抛不掉OO的影响。
说实话,我每当在midp里面要用到anti-OO的代码的时候,
自己都会加个注释://ugly
呵呵
写了1年了 还是这种思想 也许我不适合做条件受限的手机端编程吧。=(
不过无所谓了 找机会跳就是了Top
10 楼starpan()回复于 2003-12-03 11:16:13 得分 0
定义的包装载不了,是什么原因?出现的错误是Cannot access directory s at line 12;请问这是为什么?是不是我定义的时候出错了,还是调用的时候,还是把包中的类摆放的位置不对呢?
Top
11 楼TODER(TOD)回复于 2003-12-04 00:29:34 得分 0
楼主很强,佩服!佩服!从中学到了不少的知识。了解了j2me的一些解决问题的办法,谢了!Top
12 楼ziyue(紫月)回复于 2004-02-10 09:48:17 得分 0
我还以为什么新的方法。Top




