J2ME中的内存泄漏

不知道主题为"J2ME中的内存泄漏"是否妥当,不过在J2ME中如果处理不好资源的创建和释放问题,也会出现类似在C/C++中的内存泄漏现象。

  J2ME中最常使用的资源无非是图片和声音。为了提高游戏的运行速度,我们通常把它们声明为全局变量,又由于手机的内存的关系,我们不能把这些资源同时加载进内存,所以我们会在使用的时候导入资源(创建对象),而把暂时不需要的资源(图片或声音)对象赋值为null(当然这是我的做法,不知道是否和大家一样)。在这期间如果处理不好,就会有些资源对象的在内存中没有清除干净,就会造成内存泄漏,结果就是可用内存越来越小。下面我就举例说明。

  1.图片资源

  要点:要为每一个图片资源声明一个对象变量

  假设在一个程序声明了2个图片对象:

  Image pic1,pic2;

  如果在某一时刻要使用pic1和pic2则:

  if(pic1==null)pic1=Image.createImage("/1.png");

  if(pic2==null)pic2=Image.createImage("/2.png");

  当这些图片用完后,就应当:

  pic1=null;

  pic2=null;

  如果需要使用另外两个图片3.png和4.png,则最好另声明两个变量对象pic3,pic4来导入它们,不要使用pic1,pic2变量来导入这两个图片,如:

  if(pic1==null)pic1=Image.createImage("/3.png");//不要这样做

  if(pic2==null)pic2=Image.createImage("/4.png");//不要这样做

  因为这样做会影响垃圾收集器对pic1,pic2对象的回收工作,从而造成内存回收不干净。

  2.声音资源(不同的平台对声音的处理方式不同)

  要点:和图片资源一样,另外在回收声音资源一定要停止声音的播放;还有在每次开始播放声音前,也要先判断一下声音的状态(简单点,直接调用stop,先让声音停下来,然后再播放),如果不先停止声音的播放,再调用其运行播  如:

  假设sound为声音对象

  释放sound资源:

  if(sound!=null)

  {

  sound.stop();

  sound=null;

  }

  这样sound的资源就可以安全的被垃圾回收器收回了

  播放声音资源:

  if(sound!=null)

  {

  sound.stop();

  sound.start();

  }

  以上就是我的经验之谈,也许有错误的地方请大家原谅。谢谢

 

 

 

今天在CSDN上浏览帖子,忽然发现一篇询问内存溢出的解决办法的帖子,有感而发写了这篇文。
我想做过J2ME的人,特别是像我这样做手机游戏的,肯定会对OutOfMemoryError这个异常深恶痛绝,尤其是在老40这样变态的机型上,甚至对这个异常都产生了恐惧。还好我现在总算不做这个机型了,对那些仍然在为这个机型移植游戏的同志们感到同情。为了能够稍微缓解一下他们的痛苦,也为了广大J2ME的从业者和爱好者能尽量减少与该异常的见面次数,CoCoMo将把自己的经验分享一下。

首先了解一下分析内存占用的方法,一般有两种:模拟器自带工具和Runtime类方法。

模拟器自带工具:WTK貌似带了一个Memory Monitor,而且许多学者人士也夸夸其谈他的使用方法,但我不知道有多少人真正在用。就我对他的了解,首先运行他你的程序会慢的一塌糊涂,这对游戏开发者来说简直是无法忍受的。但我出于研究目的仍然让他跑了半个小时才发现原来他根本无法显示正确的内存占用量,我载入一张很大的图片后他的内存线好像只出现了微微的波动又停留在原位,呵,看来的确是拿出来秀的。我一般使用的是7210模拟器自带的内存监视器,模拟的很准,但唯一的缺点是内存太少,才200K。我也见某些人使用3220的模拟器监视内存,好像内存稍微大一点,我还没来得及尝试就再也不用为老40写程序了,庆幸。
Runtime类方法:我经常用这个语句System.out.println(Runtime.getRuntime().freeMemory());后来集成进了我的引擎,他能够显示当前剩余内存。不记得有多少次我用它在老40上来寻找内存占用峰值。

了解了分析内存的方法,来看看内存占用的罪魁祸首:程序和资源。

程序:类会被编译成class字节码文件随MIDlet的启动加载进内存,而且是一次性全部加入。也就是说MIDlet里类个数越多、单个类程序越长、类内字符串常量及数据越多,编译后的class文件就越大,载入后占用的内存也越多。我经常在MIDlet类的构造函数里用Runtime方法来查看MIDlet启动后整个程序占用内存量。
优化方法:
1.某些同志将MIDlet程序写成两个类来减少内存占用量,但是以牺牲Java的OOP特性为代价的。在程序比较大时这种弊端将尤为显见。而且CoCoMo曾经遇到过单个类过大,载入时间过长而违反百宝箱有关Logo 6秒时间限制的情形。因而我现在的程序加带引擎一般都是6-7个类。
2.尽量编写优雅的代码,减少函数数量,在程序发布时去掉try catch,最大限度的减少程序行数,这一般都是在老40上没有办法的办法,现在CoCoMo已经不靠这个来省内存了。
3.将数据及字符串写进文件,在用时方载入内存,不用时设为null。
4.I/O操作getClass().getResourceAsStream(file);、数据库操做RecordStore.openRecordStore(name, true);、声音创建Manager.createPlayer();、图像创建Image.createImage(file);会在短时间内占用大量内存且过后释放,如果MIDlet程序内存剩余量不足则会在这些函数频繁调用时发生内存溢出,产生所谓的内存峰值,尤其在老40上比较普遍。当你再次与讨厌的OutOfMemoryError碰面时,多用Runtime查找内存峰值发生位置并尽量将这些语句分开调用,并灵活运用System.gc()来及时回收。

资源:
  图片:是占用内存的大户,尤其是手机游戏图片资源众多。对图片资源在内存中占用量的计算成为J2ME游戏开发者的经常性工作,CoCoMo来解释一下如何计算图片在内存中的占用量:
内存占用量=宽*高*像素字节数,其中像素字节数因机型而异。
例如一张64*64的图片在7210上的内存占用量=64*64*1.5=6144(字节)=6K、在S60上的内存占用量=64*64*2=8192(字节)=8K。像素字节数因机型而异,例如7210是4096色机型,也就是说用12位来表示一个像素,所以乘上1.5,而S60是65536色的机型,用16位来表示一个像素,所以乘上2。
优化方法:
有些人认为压缩图片可以节省内存,这种想法是错误的。根据上面的解释图片载入内存后只和宽高有关系,和图片数据量大小没有任何关系,压缩图片只能减少jar大小而不能减少内存占用量。
1.静态法:减小图片大小,宽高小了结果当然小了。根据这个思路出现了动画编辑器之类的工具,像gameloft的波斯王子,人物被分割后使人体的部位可以重用,各部位紧凑放置都是为了较少图片大小,充分利用图片中的每一寸空间。
2.动态法:减少同一时刻载入内存的图片数。CoCoMo曾经在火影武士项目中遇到过这种情况,当时有6种怪物,如果同时载入内存在老40上肯定爆掉了,但是每关只出现两到三种怪物,所以每一关只需要载入该关出现的怪物图片即可。现在想起来当时做这个项目在老40上溢出频出,真把我搞死了。
   声音:声音也是比较耗用内存的资源,声音中音轨所占的byte会转化成字节流被载入到内存中。因而减少音轨所占byte即可减少内存耗用量。目前gameloft的做法是用声音转化工具将mid转化为ott,然后变为ByteArrayInputStream字节流来创建Player。

 

MOTO 小C系列
常见机型:C650
手机屏幕:128*128
游戏屏幕:128*116
非全屏屏幕:128*100
JAVA联网:CMWAP需要代理
字体大小:17*17,一行约7个中文字,内置一种字体,任何字体选项均为默认字体
MIDP:2.0
CLDC:1.0
JAVA单个容量限制:标准100K(实际无限制,小于手机本身内存)
JAVA堆栈容量:800K
特别1:支持MOTO FUNLIGHT API
特别2:支持MOTO 3D API
特别3:开启摄像头、内部文件访问权限等需要授权
特别4:C650机型:setMediaTime该机型不支持,playerUpdate传过来的player是副本,所以应该用
equal而不是==。
 
--------------------------------------------------------------------------------
MOTO C550/C370/E380系列
手机屏幕:96*65
游戏屏幕:96*64
非全屏屏幕:96*64
JAVA联网:CMWAP需要代理
字体大小:不明,可参考MOTO C
MIDP:1.0
CLDC:1.0
JAVA单个容量限制:100K标准(实际不明)
JAVA堆栈容量:512K
特别1:支持MOTO GAME API,可实现相当于MIDP2.0的功能。
--------------------------------------------------------------------------------
MOTO E398、V600系列
手机屏幕:176*220
游戏屏幕:176*204
非全屏屏幕:176*182
JAVA联网:CMWAP需要代理
字体大小:17*17 一行约10个中文字,内置一种字体,任何字体选项均为默认字体。
MIDP:2.0
CLDC:1.0
JAVA单个容量限制:无限制,小于手机本身内存
JAVA堆栈容量:800K
特别1:E398支持MOTO FUNLIGHT API
特别2:支持MOTO 3D API
特别3:开启摄像头、内部文件访问权限等需要授权
特别4:V300系列,键值正好与E398互为相反数,可以归为同一个版本,取键值的判断其绝对值。
--------------------------------------------------------------------------------
MOTO C975/C980/V980系列
手机屏幕:176*220
游戏屏幕:176*204
非全屏屏幕:176*182
JAVA联网:CMWAP需要代理
字体大小:内置三种字体
MIDP:2.0
CLDC:1.1
JAVA单个容量限制:无限制,小于手机本身内存
JAVA堆栈容量:1.5M
特别1:支持标准 3D API
特别2:支持蓝牙
--------------------------------------------------------------------------------
MOTO E680系列
手机屏幕:240*320
游戏屏幕:240*320
JAVA联网:CMWAP需要代理、直联
字体大小:内置三种字体
MIDP:2.0
CLDC:1.1
JAVA单个容量限制:无限制,小于手机本身内存
JAVA堆栈容量:1.5M(预想)
特别1:支持标准 3D API
特别2:支持蓝牙
特别3:E680上5个空格占一个字符宽度
特别4:E680加载代码是分段加载,尽量避免写超长的方法,否则可能会有延迟。
--------------------------------------------------------------------------------
NOKIA S40 V1
手机屏幕:128*128
游戏屏幕:128*128(FullCanvas)
非全屏屏幕:128*???
JAVA联网:CMWAP直接联
字体大小:三种字体大小,最小字体12*12,一行约10个中文字
MIDP:1.0
CLDC:1.0
JAVA单个容量限制:64KB
JAVA堆栈容量:不明
特别1:按键会有延迟,中断后原线程还会在后台继续运行直到调用repaint,内存开销不当会死机
----------------------------------------------------------------------------------
NOKIA S40 V2
手机屏幕:128*128
游戏屏幕:128*128(FullCanvas 或 setfullscreenmode(ture))
非全屏屏幕:128*???
JAVA联网:CMWAP直接联
字体大小:三种字体大小,最小字体12*12,一行约10个中文字
MIDP:2.0
CLDC:1.0
JAVA单个容量限制:110~128KB不等
JAVA堆栈容量:不明
-------------------------------------------------------------------------------------
NOKIA 6230i
手机屏幕:128*128
游戏屏幕:208*208(这里指分辨率)
JAVA联网:CMWAP直接联
字体大小:不明,可参考S40
MIDP:2.0
CLDC:1.0
JAVA单个容量限制:不明
JAVA堆栈容量:不明
--------------------------------------------------------------------------------------
NOKIA S60 MIDP1.0
手机屏幕:176*208
游戏屏幕:176*208(FullCanvas)
非全屏屏幕:176*144
JAVA联网:CMWAP直接联
字体大小:不明,一行可显示约12-13个中文字
MIDP:1.0 (但是可增加多媒体播放API)
CLDC:1.0
JAVA单个容量限制:不明
JAVA堆栈容量:不明
特别1:3650机型:setClip和drawRegion搭配不能正确设置裁减框。
特别2:3650机型:频繁I/O操作会死机,应尽量在游戏初始化时将数据一次读入。
特别3:N-Gage机型:在背景缓冲上setClip和drawRegion搭配完全不能设置裁减框声音播放有问题,建
特别4:N-Gage机型:声音播放有问题,建议在I/O操作等跟系统底层有关调用之后再播放声音

---------------------------------------------------------------------------------------
NOKIA S60 MIDP2.0
手机屏幕:176*208
游戏屏幕:176*208(FullCanvas 或 setfullscreenmode(ture))
非全屏屏幕:176*144
JAVA联网:CMWAP直接联
字体大小:不明,一行可显示约12-13个中文字
MIDP:2.0
CLDC:1.0
JAVA单个容量限制:不明
JAVA堆栈容量:不明
特别1:6600机型:调用readFully不能按指定字节数读取,readByte代替。
特别2:6600机型:setClip和drawRegion搭配在欧版6600上不能正确设置裁减框,导致绘图错误
特别3:7610机型:drawRegion在这个机型上会拖慢速度,建议使用Nokia UI API上的drawImage。
特别4:7610机型:绘图函数调用不当会当机。
特别5:6681机型:频繁I/O操作会死机,应尽量在游戏初始化时将数据一次读入。
特别6:6681机型:使用2.0的drawRegion会造成内存泄露,尽量减少使用翻转,尤其是画地图时应尽量使用1.0的drawImage来实现

----------------------------------------------------------------------------------------
索爱K700C
手机屏幕:176*220
游戏屏幕:176*220(setfullscreenmode(true))
游戏屏幕:176*208(com.nokia.mid.ui.FullCanvas)
非全屏屏幕:176*176(setfullscreenmode(false))
JAVA联网:CMWAP需要代理
字体大小:不明,一行中文字数约10个,内置一种字体,任何字体选项均为默认字体。
MIDP:2.0
CLDC:1.1
JAVA单个容量限制:???
JAVA堆栈容量:512K(实际使用中感觉不止)
特别1:支持NOKIA UI API,但是drawpixels(),getpixels()这2个表现差劲不能使用
特别2:支持标准3D API
特别3:单个类文件不能超过70K(JAR包压缩后的大小),否则无法加载
------------------------------------------------------------------------------------
波导S689
手机屏幕:128*160
游戏屏幕:128*144
非全屏屏幕:128*128(估计)
JAVA联网:CMWAP需要代理
字体大小:不明, 一行约8个中文字,内置一种字体
MIDP:2.0
CLDC:1.0
JAVA单个容量限制:200K
JAVA堆栈容量:512K
------------------------------------------------------------------------------
阿尔卡特 OT556/557
手机屏幕:128*160
游戏屏幕:128*160
非全屏屏幕:128*129
JAVA联网:CMWAP需要代理
字体大小:14*14,一行中文字个数约8个,内置一种字体font(0,0,0)
MIDP:2.0
CLDC:1.0
JAVA单个容量限制:256k
JAVA堆栈容量:512K
----------------------------------------------------------------------------------
三星X108/X608
手机屏幕:128*128
游戏屏幕:128*128(全屏补丁实现)
非全屏屏幕:128*110
JAVA联网:CMWAP需要代理
字体大小:不明,一行中文字个数不明,内置一种字体font(0,0,0)
MIDP:1.0
CLDC:1.0
JAVA单个容量限制:???
JAVA堆栈容量:不明

 

 


多余的话不多说了网上很多,这里写一些自己总结的经验

最占内存的是图片,所以要优先考虑优化图片,能不用就不用吧

   a = new Student() //a不为null   这样的代码要注意,尤其是图片很容易就内存泄露了,大家可以试试弄几张比较大的图 连续赋值几次就挂了

    g,drawString("游戏时间:"+time +...,x,y,0); 和上面其实是一类情况 因为在执行+的时候系统会重新创建一个新的str 对象,尽量用StringBuffer代替string,string很容易产生垃圾

    尽量用数组代替vector(),少用二维数组,二维数组访问时间是一维的2倍,如果能用一维的代替就把它换成一维的数组吧,少用数组即使是一维的数值也没有直接变量访问速度快

    不要在循环里面创建对象 ,可以先创建对象再在循环里面初始化

   异常处理很占资源,如果可以尽量把异常处理放在一块

      paint()方法里面不要放太多复杂的计算,否则在性能比较低的机器很容易挂掉,而且也很影响屏幕的刷新速度

    图片处理很费cpu 和资源,如果能够让美工做一些翻转,放大缩小。。的图片代替,就不要用算法了

   关于自定义字体,透明效果,多媒体处理...比较占资源的工作,如果不是针对高端手机或有针对性的项目,就不要实现了,低端手机根本不行

   还有就是也是最重要的 代码 算法的优化

 

 


long  freeMemory=Runtime.getRuntime().freeMemory();//获得手机剩余堆栈内存 
long  totalMemory=Runtime.getRuntime().totalMemory();//获得手机总堆栈内存  智能机总堆栈内存是动态分配的

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值