Java 为什么我的应用占用这么多内存?
所以我用位图和surfaceview为一个学校项目制作了一个游戏应用程序。但是应用程序本身占用了太多内存!!只有当你启动它时,它才能获得高达60mb的内存,而且你玩得越多,它的内存就越高(有一次它达到了90mb的内存,游戏严重滞后) 在观看了Google I/O 2011()之后,我再次强调这可能是内存泄漏,因为该应用程序是这样启动的:Java 为什么我的应用占用这么多内存?,java,android,bitmap,Java,Android,Bitmap,所以我用位图和surfaceview为一个学校项目制作了一个游戏应用程序。但是应用程序本身占用了太多内存!!只有当你启动它时,它才能获得高达60mb的内存,而且你玩得越多,它的内存就越高(有一次它达到了90mb的内存,游戏严重滞后) 在观看了Google I/O 2011()之后,我再次强调这可能是内存泄漏,因为该应用程序是这样启动的:播放2分钟后,它就这样结束了: 该应用程序本身看起来尽可能简单,具有8位图形,颜色不多: 我使用的所有图像的重量都只有400kb那么到底为什么需要这么多内存?!
播放2分钟后,它就这样结束了:
该应用程序本身看起来尽可能简单,具有8位图形,颜色不多: 我使用的所有图像的重量都只有400kb那么到底为什么需要这么多内存?!我想可能是声音,但所有声音加起来只有4.45mb的内存,这相当于应用程序所需容量的1/10。我知道位图需要很多内存,但这太荒谬了 这是我的加载:
public GameView(Context c) {
// TODO Auto-generated constructor stub
super(c);
this.c = c;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
ScoreParticleP = new PointF();
NewScoreParticleP = new PointF();
int srcWidth = options.outWidth;
int srcHeight = options.outHeight;
// it=blocks.iterator();
// Decode with inSampleSize
options.inJustDecodeBounds = false;
options.inDither = false;
options.inScaled = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
this.setKeepScreenOn(true);
WindowManager wm = (WindowManager) c
.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
this.screenw = display.getWidth();
this.screenh = display.getHeight();
this.differencew = (double) screenw / normalw;
this.differenceh = (double) screenh / normalh;
try{
mediaPlayer = MediaPlayer.create(c, R.raw.nyan);
while(mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(c, R.raw.nyan);
}
mediaPlayer.setLooping(true);
if(mediaPlayer!=null)
mediaPlayer.start();
}
catch(Exception e){
}
try{
mediaPlayer2 = MediaPlayer.create(c, R.raw.remix);
while(mediaPlayer2==null){
mediaPlayer2 = MediaPlayer.create(c, R.raw.remix);
}
mediaPlayer2.setLooping(true);
}
catch(Exception e){
}
try{
mediaPlayer3 = MediaPlayer.create(c, R.raw.weed);
while(mediaPlayer3==null){
mediaPlayer3 = MediaPlayer.create(c, R.raw.weed);
}
mediaPlayer3.setLooping(true);
}
catch(Exception e){
}
SharedPreferences prefs2 = c.getSharedPreferences(
"Sp.game.spiceinspace", Context.MODE_PRIVATE);
counter2 = prefs2.getInt("score", 0);
this.sprite = BitmapFactory.decodeResource(getResources(),
R.drawable.sprite, options);
this.sprite = Bitmap.createScaledBitmap(sprite, sprite.getWidth() * 3,
sprite.getHeight() * 3, false);
this.heart = BitmapFactory.decodeResource(getResources(),
R.drawable.heart);
this.explosionheart=BitmapFactory.decodeResource(getResources(),
R.drawable.explosionheart);
this.heart = Bitmap.createScaledBitmap(heart, heart.getWidth() * 3,
heart.getHeight() * 3, false);
currentSpeed = new PointF(0, 0);
currentDirection = new Point(0, 0);
currentPosition = new Point(350, 350);
this.background = BitmapFactory.decodeResource(getResources(),
R.drawable.space);
this.background2=BitmapFactory.decodeResource(getResources(),
R.drawable.space2);
this.electricExplosion = BitmapFactory.decodeResource(getResources(),
R.drawable.effect_explosion);
this.normalexplison = BitmapFactory.decodeResource(getResources(),
R.drawable.effect_explosion2);
this.background = Bitmap.createScaledBitmap(background,
background.getWidth() * 5, background.getHeight() * 5, false);
this.background2 = Bitmap.createScaledBitmap(background2,
background2.getWidth() * 5, background2.getHeight() * 5, false);
this.lost = BitmapFactory.decodeResource(getResources(),
R.drawable.gameover);
this.lostNew = BitmapFactory.decodeResource(getResources(),
R.drawable.gameovernew);
lostNew = FitAllDevices(lostNew);
lost = FitAllDevices(lost);
this.alien = BitmapFactory.decodeResource(getResources(),
R.drawable.mob_alien);
this.coin = BitmapFactory.decodeResource(getResources(),
R.drawable.item_coin);
partic = BitmapFactory.decodeResource(getResources(),
R.drawable.particle_star);
fire = BitmapFactory.decodeResource(getResources(),
R.drawable.particle_fire);
smoke = BitmapFactory.decodeResource(getResources(),
R.drawable.particle_smoke);
partic = Bitmap.createScaledBitmap(partic, partic.getWidth() * 2,
partic.getHeight() * 2, false);
fire = Bitmap.createScaledBitmap(fire, fire.getWidth() * 2,
fire.getHeight() * 2, false);
smoke = Bitmap.createScaledBitmap(smoke, smoke.getWidth() * 2,
smoke.getHeight() * 2, false);
electricExplosion = Bitmap.createScaledBitmap(electricExplosion,
electricExplosion.getWidth() * 2,
electricExplosion.getHeight() * 2, false);
normalexplison = Bitmap.createScaledBitmap(normalexplison,
normalexplison.getWidth() * 3,
normalexplison.getHeight() * 3, false);
this.alien = Bitmap.createScaledBitmap(alien, alien.getWidth() * 3,
alien.getHeight() * 3, false);
asteroid = BitmapFactory.decodeResource(getResources(),
R.drawable.mob_astroid);
bomb = BitmapFactory.decodeResource(getResources(),
R.drawable.mob_spacebomb);
asteroid = Bitmap.createScaledBitmap(asteroid, asteroid.getWidth() * 3,
asteroid.getHeight() * 3, false);
bomb = Bitmap.createScaledBitmap(bomb, bomb.getWidth() * 3,
bomb.getHeight() * 3, false);
goldasteroid = BitmapFactory.decodeResource(getResources(),
R.drawable.mob_goldastroid);
goldasteroid = Bitmap.createScaledBitmap(goldasteroid,
goldasteroid.getWidth() * 3, goldasteroid.getHeight() * 3,
false);
mushroom = BitmapFactory.decodeResource(getResources(),
R.drawable.item_mushroom);
mushroom = Bitmap.createScaledBitmap(mushroom, mushroom.getWidth() * 4,
mushroom.getHeight() * 4, false);
coin = Bitmap.createScaledBitmap(coin, coin.getWidth() * 2,
coin.getHeight() * 2, false);
drug = BitmapFactory
.decodeResource(getResources(), R.drawable.item_not);
drug = Bitmap.createScaledBitmap(drug, drug.getWidth() * 4,
drug.getHeight() * 4, false);
rocket = BitmapFactory.decodeResource(getResources(),
R.drawable.item_rocket);
rocket = Bitmap.createScaledBitmap(rocket, rocket.getWidth() * 4,
rocket.getHeight() * 4, false);
electricExplosion = FitAllDevices(electricExplosion);
alien = FitAllDevices(alien);
normalexplison = FitAllDevices(normalexplison);
explosionheart = FitAllDevices(explosionheart);
mushroom = FitAllDevices(mushroom);
drug = FitAllDevices(drug);
rocket = FitAllDevices(rocket);
bomb = FitAllDevices(bomb);
asteroid = FitAllDevices(asteroid);
goldasteroid = FitAllDevices(goldasteroid);
sprite = FitAllDevices(sprite);
heart = FitAllDevices(heart);
player = new Spicy(sprite, heart);
hit = soundPool.load(c, R.raw.hit, 1);
pass = soundPool.load(c, R.raw.win, 1);
//remix = soundPool.load(c, R.raw.remix, 1);
destroy = soundPool.load(c, R.raw.destroy, 1);
aliensound = soundPool.load(c, R.raw.alien, 1);
alienexpload = soundPool.load(c, R.raw.explosion2, 1);
//particlesound = soundPool.load(c, R.raw.particle, 1);
bigexplosion=soundPool.load(c, R.raw.explosion, 1);
gameLoopThread = new GameLoopThread(this);
this.requestFocus();
this.setFocusableInTouchMode(true);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
if (gameLoopThread.getState()==Thread.State.TERMINATED) {
gameLoopThread = new GameLoopThread(g);
}
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
我做错什么了吗?我的应用程序只是一个小游戏,一开始它启动缓慢,但你玩得越多,就会有更多的位图出现,如果屏幕上有很多位图,我会理解这个内存量,但当屏幕上只有玩家和背景时,它需要60mb的内存
我很乐意给任何人发电子邮件,让他们自己看看这个应用程序有多简单,但它需要多少内存
编辑: 我提到,随着时间的推移,应用程序占用的内存越来越多,我明白这与我创建新位图并将其四处移动然后删除有关,玩得越多,创建的位图就越多,但我会尽力在之后立即删除它们并回收它们,以确保它们被垃圾收集器收集。我想知道怎样才能最大限度地减少使用量,同时使我的游戏仍然可以玩: 这就是我如何“繁殖”mob(mob获取我在onLoad上加载的位图): 在onDraw上,我确保移除暴徒,这样当他们不在屏幕上时,他们就不会占用额外的内存:
Iterator<Map.Entry<Point, Mob>> spawnedEntry = spawned
.entrySet().iterator();
while (spawnedEntry.hasNext()) {
Map.Entry<Point, Mob> entry = spawnedEntry.next();
if(entry.getValue().destroycomplete||entry.getValue().dissapired){
spawnedEntry.remove();
}
else
entry.getValue().draw(canvas, entry.getKey());
编辑2: 这是eclipse的内存工具告诉我的:
这肯定是位图
为什么我的应用程序在启动时会占用这么多内存 原始图像文件已压缩。您正在解压缩它们并在内存中存储完整的位图。(关于行字节*字节高度;) 你也在重新调整它们的规模;例如,背景被缩放到原始大小的五倍。由于图像有两个维度,内存消耗按二次方比例缩放 示例:大小为500x500的图像;它在行之间分配4个字节(32位模式)。 这将导致位图大小为500x4 x 500=1MB 如果将此图像缩放2倍,则分配的内存不会是原来的两倍,而是:1000x4 x 1000=4MB 我能做什么?
- 如果不需要alpha通道,可能需要减少位图的位深度。例如,使用
进行解码Bitmap.Config.RGB_565
- 通过指定样本大小,不要加载比需要大的位图。(更多信息请参见此处:)
- 确保重复使用尽可能多的位图
- 仅在需要时加载位图。你同时需要两个背景吗
- 你的背景似乎只是一个渐变;您可以使用该类来绘制它,从而节省了巨大的背景图像。(这同样适用于您的方块,它们不应该只是占位符。)
- 确保你不会不断创造新的暴徒。将“死亡”暴徒保存在单独的列表中,并在需要时将其放回演员列表中。只有当你的“待决”暴徒用完时才创建新的暴徒
- 不要在经常被调用的方法中创建对象。(例如:任何 为此,请使用draw()方法。)
如果您在pre-Honeycomb上进行测试,您需要回收任何分配的位图,否则它们可能不会从本机内存中释放。如果您的应用程序随着时间的推移占用更多内存,我预计问题不会出现在您的加载中。我的第一个猜测是,在游戏逻辑的某个地方,你正在重新创建一个对象并放弃旧的实例,而你最好重用旧的对象。同样,请记住,仅仅因为你的图像在文件形式(jpg、png等)上相对较小,这并不能转化为它们在RAM中的样子。在文件格式中,图像被压缩以节省空间。一旦您解码它们,它们就会被放大为像素的原始表示,这要大得多,尤其是使用ARGB8888格式时。再加上图像的放大(上面的代码就是这么做的),你的RAM使用率就大大提高了。@CoreyOgburn我的问题分为两个,第一个是应用程序只有在启动时才占用了大量的RAM。我想相信,对于5mb文件来说,60mb是不正常的。第二个问题是,随着时间的推移,我的应用程序占用的内存越来越多,我也不明白这一点,因为我确保回收并删除所有未显示的位图。@LarrySchiefer我看到了,那么我该如何减少它,我看到过外观更好、占用内存更少的应用程序,而且我认为缩放不应该影响ram,因为它与刚放大的像素的原始表示相同。它可能使用mip映射进行缩放。这将创建多个精灵实例。每个尺寸一个。我已经编辑了这个问题,这样你就可以理解为什么我的应用会随着时间的推移使用更多的内存。我部分理解你的答案,我理解位图存储图像的所有数据并对其进行解压缩,但我不理解它与重新调整大小有什么关系。如果我说位图=createScaledBitmap(位图);旧位图不应该替换为新位图吗,这意味着重新缩放不应该影响内存?你也能为这个问题提供解决方案吗?我能做些不会破坏比赛质量的事情吗
Iterator<Map.Entry<Point, Mob>> spawnedEntry = spawned
.entrySet().iterator();
while (spawnedEntry.hasNext()) {
Map.Entry<Point, Mob> entry = spawnedEntry.next();
if(entry.getValue().destroycomplete||entry.getValue().dissapired){
spawnedEntry.remove();
}
else
entry.getValue().draw(canvas, entry.getKey());
if(!MobEffectstarted)
if(!destroycomplete)
c.drawBitmap(mob,p.x,p.y, null);
else
mob.recycle();