草庐IT

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

coder 2023-11-26 原文

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

在观看了 Google I/O 2011 ( https://www.youtube.com/watch?v=_CruQY55HOk ) 之后,我认为这可能是内存泄漏,因为应用程序是这样启动的:
播放 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) {
            }
        });
    }

我做错了什么吗?我的应用程序只是一个小的位图游戏,从一侧出来并转到另一侧,起初它开始很慢,但你玩的越多,位图就越多,如果有很多位图,我会理解这么多的 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的内存工具告诉我的:
它肯定是位图。


最佳答案

为什么我的应用程序在启动时会占用这么多 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/

有关java - 为什么我的应用占用这么多内存?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  4. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  7. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  8. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  9. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  10. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

随机推荐