gpt4 book ai didi

java - 为什么我的应用占用这么多内存?

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:08:01 26 4
gpt4 key购买 nike

因此,我为一个学校项目使用位图和表面 View 制作了一个游戏应用程序。但是应用程序本身占用了太多内存!!只有当您启动它时,它才能获得高达 60mb 的 ram,并且您玩得越多,它就会变得越高(有一次它达到了 90mb 的 ram,并且游戏非常滞后)。

在观看了 Google I/O 2011 ( https://www.youtube.com/watch?v=_CruQY55HOk ) 之后,我认为这可能是内存泄漏,因为应用程序是这样启动的:enter image description here
播放 2 分钟后,结果是这样的:
enter image description here

应用程序本身看起来尽可能简单,具有 8 位图形且颜色不多:enter image description here

我使用的所有图像只有 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) {
}
});
}

我做错了什么吗?我的应用程序只是一个小的位图游戏,从一侧出来并转到另一侧,起初它开始很慢,但你玩的越多,位图就越多,如果有很多位图,我会理解这么多的 ram屏幕,但当屏幕上只有播放器和背景时,它需要 60mb!

我很乐意将应用程序通过电子邮件发送给任何人,让他们自己尝试看看它有多么简单,但无缘无故需要多少 ram..


编辑:

我提到该应用程序会随着时间的推移占用更多内存,我知道这与我创建新位图并将它们四处移动然后删除它们有关,而且您玩得越多,创建的位图就越多,但是我尽力在之后立即删除它们并回收它们以确保它们被垃圾收集器收集。我想知道如何才能最大限度地减少使用量并仍然让我的游戏可玩:

这就是我“生成”生物的方式(生物获取我在 onLoad 上加载的位图):

private void spawnMob() {
if (timer2 == 0) {
int mobtype = randInt(1, 40);
switch (mobtype) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
Mob m = new Mob(alien, MobEffect.comeback, 1);
Point p = new Point(0, 0);
p.y = randInt(0, screenh - alien.getHeight());
p.x = screenw + alien.getWidth();
spawned.put(p, m);
break;

case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
case 32:
Mob m2 = new Mob(asteroid, MobEffect.dissapire, 0);
Point p2 = new Point(0, 0);
p2.y = randInt(0, screenh - asteroid.getHeight());
p2.x = screenw + asteroid.getWidth();
spawned.put(p2, m2);
break;
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
Mob m3 = new Mob(goldasteroid, MobEffect.dissapire, 1);
Point p3 = new Point(0, 0);
p3.y = randInt(0, screenh - goldasteroid.getHeight());
p3.x = screenw + goldasteroid.getWidth();
spawned.put(p3, m3);
case 40:
if (counter > 3) {
Mob m4 = new Mob(bomb, MobEffect.expload, 1, 5, false,
false);
Point p4 = new Point(0, 0);
p4.y = randInt(0, screenh - bomb.getHeight());
p4.x = screenw + bomb.getWidth();
spawned.put(p4, m4);
} else {
Mob m5 = new Mob(asteroid, MobEffect.dissapire, 0);
Point p5 = new Point(0, 0);
p5.y = randInt(0, screenh - asteroid.getHeight());
p5.x = screenw + asteroid.getWidth();
spawned.put(p5, m5);
}
break;
}
if (rocketspeed >= 10) {
timer2 = randInt(1, 8);
} else {
if (bleedoff != 35) {
if (bleedoff > 1)
timer2 = randInt(35 / (int) bleedoff,
150 / (int) bleedoff);
else
timer2 = randInt(35, 150);
} else
timer2 = randInt(1, 10);
}
} else {

timer2--;

}
}

在 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());

也在 Mob 类上:

if(!MobEffectstarted)
if(!destroycomplete)
c.drawBitmap(mob,p.x,p.y, null);
else
mob.recycle();

编辑2:

这是eclipse的内存工具告诉我的: enter image description here
它肯定是位图。


enter image description here enter image description here

最佳答案

为什么我的应用程序在启动时会占用这么多 RAM?

您的原始图像文件已压缩。您正在解压缩它们并将完整的位图存储在内存中。 (关于 rowBytes * 字节高度;find out bitmap size)您还重新调整了其中很多的大小;例如,背景被缩放到原始大小的五倍。由于图像具有二维,因此内存消耗呈二次方增长。

示例:尺寸为 500x500 的图像;它在行之间分配 4 个字节(32 位模式)。这导致位图大小为 500x4 x 500 = 1MB。

如果将此图像缩放 2 倍,则分配的内存不会增加两倍,而是:1000x4 x 1000 = 4MB

我能做什么?

  • 如果您不需要 alpha channel ,您可能希望减少位图的位深度。例如使用 Bitmap.Config.RGB_565 解码。
  • 通过指定样本大小,不要加载比需要更大的位图。 (更多相关信息:Loading Large bitmaps)
  • 确保尽可能多地重复使用位图。
  • 仅在需要时加载位图。您是否同时需要两种背景?
  • 你的背景似乎只是一个渐变;你可以使用LinearGradient类来绘制它,省去了巨大的背景图像。 (这同样适用于您的方 block ,它们不应该只是占位符。)

关于代码中的内存泄漏:

  • 确保你不会不断地制造新的生物。将“死亡”的生物保存在一个单独的列表中,并在需要时将它们放回 Actor 列表中。仅当您实际用完“待定”暴民时才创建新的。
  • 不要在经常调用的方法中创建对象。 (例如:任何draw() 方法。)

如果您在 pre-Honeycomb 上进行测试,您需要回收所有已分配的位图,否则它们可能无法从 native 内存中释放。

关于java - 为什么我的应用占用这么多内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28990100/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com