内存不足异常 + 分析 hprof 文件转储

Posted

技术标签:

【中文标题】内存不足异常 + 分析 hprof 文件转储【英文标题】:out of memory exception + analyzing hprof file dump 【发布时间】:2014-08-01 01:55:11 【问题描述】:

这与这个问题有关

java.lang.OutOfMemoryError at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)

我创建了有问题的转储文件.. 它提供了以下信息

One instance of "byte[]" loaded by "<system class loader>" occupies 1,10,59,216
(51.02%) bytes. The memory is accumulated in one instance of "byte[]" 
 loaded by "<system class loader>".

Keywords byte[]

那么现在可以做什么?我如何清除问题?

我的 list_objects[context]-入站文件

CLASS NAME                                                                 SHALLOW HEAP   RETAINED HEAP  
byte[11059200] @ 0xb4979590                                               |  1,10,59,216 |   1,10,59,216
mBuffer android.graphics.Bitmap @ 0xb3dc68d8                              |48            | 48
mBitmap android.graphics.drawable.BitmapDrawable @ 0xb3dbba60             | 72           | 144
mBackground android.widget.RelativeLayout @ 0xb3db3fc0                    |512           | 10,144
mBitmap android.graphics.drawable.BitmapDrawable$BitmapState @ 0xb3dc0068 |40          | 40
mBitmapState android.graphics.drawable.BitmapDrawable @ 0xb3dbba60        |72          |  144
referent java.lang.ref.WeakReference @ 0xb3dc2d68                         |24          |  24

请帮助我绝望。如何解决内存问题??

我的 home_screen.java

 protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.home_page);
    main();
 private void main() 
    // TODO Auto-generated method stub


    final Button home;
    final Button aboutus;
    final Button contacts;
    final Button clients;
    final Button services;

    try
    

    home = (Button)findViewById(R.id.btnHome);
    aboutus = (Button)findViewById(R.id.btnAboutus);
    clients = (Button)findViewById(R.id.btnClients);
    contacts = (Button)findViewById(R.id.btnContacts);
    services = (Button)findViewById(R.id.btnServices);

    home.setOnClickListener(new OnClickListener() 

        @Override
        public void onClick(View v) 
            // TODO Auto-generated method stub
            Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.home1);
            Drawable d = new BitmapDrawable(getResources(),b);              
            home.setBackgroundDrawable(d);
            System.gc();
            Intent myIntent = new Intent(Home_Screen.this, Button_Anime.class);
            startActivity(myIntent);
        
    );
    aboutus.setOnClickListener(new OnClickListener() 

        @Override
        public void onClick(View v) 
            // TODO Auto-generated method stub
            Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.about1 );
            Drawable d = new BitmapDrawable(getResources(),b); 
            aboutus.setBackgroundDrawable(d);
            Intent myIntent = new Intent(Home_Screen.this, AboutUs.class);
            startActivity(myIntent);
        
    );
    clients.setOnClickListener(new  OnClickListener() 

        @Override
        public void onClick(View v) 
            // TODO Auto-generated method stub

            Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.clients1 );
            Drawable d = new BitmapDrawable(getResources(),b); 
            clients.setBackgroundDrawable(d);
            Intent myIntent = new Intent(Home_Screen.this, Clients.class);
            startActivity(myIntent);
        
    );
    contacts.setOnClickListener(new OnClickListener() 

        @Override
        public void onClick(View v) 
            // TODO Auto-generated method stub

            Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.contact1);
            Drawable d = new BitmapDrawable(getResources(),b);
            contacts.setBackgroundDrawable(d);
            Intent myIntent = new Intent(Home_Screen.this, Contacts.class);
            startActivity(myIntent);
        
    );
    services.setOnClickListener(new OnClickListener() 

        @Override
        public void onClick(View v) 
            // TODO Auto-generated method stub

            Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.services1 );
            Drawable d = new BitmapDrawable(getResources(),b);
            services.setBackgroundDrawable(d);
            Intent myIntent = new Intent(Home_Screen.this, Services.class);
            startActivity(myIntent);
        
    );

    
    catch(Exception e)
    
        e.printStackTrace();
    

【问题讨论】:

粘贴您的代码。以便我们进行分析。 @DevCarlsberg 我已经发布了我的主文件.. 请检查.. 老兄通过My this Answer会帮助你。 我已经完成了所有这些.. 并且仍然遇到同样的错误.. 我的文件都是 30-40kb 大小,是的,我已将堆设置为大@DevCarlsberg 好的,让我给你解码你的位图的代码。它会解决你的问题 【参考方案1】:

这个想法是对您的图像进行下采样,使其在较小的屏幕上看起来不错,并且您不必将整个位图加载到内存中。

1) 首先获取要显示的 ImageView/ 屏幕的大小。

2) 通过传入 BitmapFactory.Options.inJustDecodeBounds 读取 Bitmap 的大小。这将为您提供位图的大小,而不是加载整个位图。

3) 获取非样本大小。计算屏幕的高度和宽度与图像高度和宽度的比值。使用最小的,以使最大的尺寸看起来不错。

4) 最后使用下面的函数来获取不会占用内存的下采样图像。

2)(代码)

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(inputStream, null, bitmapOptions);
int imageWidth = bitmapOptions.outWidth;
int imageHeight = bitmapOptions.outHeight;
inputStream.close();

4)(代码)

private Bitmap downscaleBitmapUsingDensities(final int sampleSize,final int imageResId)
  
  final Options bitmapOptions=new Options();
  bitmapOptions.inDensity=sampleSize;
  bitmapOptions.inTargetDensity=1;
  final Bitmap scaledBitmap=BitmapFactory.decodeResource(getResources(),imageResId,bitmapOptions);
  scaledBitmap.setDensity(Bitmap.DENSITY_NONE);
  return scaledBitmap;
  

【讨论】:

【参考方案2】:

在清单中添加 largeHeap="true" 可能会有所帮助。这将允许您的应用程序使用更多内存。

见:http://developer.android.com/guide/topics/manifest/application-element.html

【讨论】:

这充其量只是一个创可贴,来自链接:“大多数应用程序不应该需要这个,而是应该专注于减少它们的整体内存使用量。”【参考方案3】:

试试下面的代码:

Resources res = getContext().getResources();
int id = R.drawable.image; 
Bitmap b = BitmapFactory.decodeResource(res, id);    
_img .setimagebitmap(b);

【讨论】:

@DevCalsberg 此代码不起作用 Eclipse 不接受它。资源 res = getContext().getResources(); home.setimagebitmap(b);这两个代码都产生错误..而且这个代码在逻辑上与我使用的代码不一样???【参考方案4】:

通常,当我在低 RAM 设备上遇到这种异常时,这是因为我有某种图像对于这种分辨率来说很昂贵(很多 kb)。 我遇到了一个奇怪的问题,因为我只使用了 xhdpi 和 hdpi 可绘制目录,在 mdpi 甚至 ldpi 设备上,将 hdpi 转换为正确的分辨率会引发此异常,因为无法调整图像大小。

这发生在任何设备上?你能检查一下你有这个低设备的特定图形吗?

使用 HPOF 文件的任何方式,您都可以看到什么样的对象,或者至少,哪个活动/视图有问题。 您需要分析所有这些数据(没有总体计划来找到它正在崩溃您的应用程序的资源),以查看哪个有问题。

希望对你有帮助,有什么问题欢迎提问。

【讨论】:

以上是关于内存不足异常 + 分析 hprof 文件转储的主要内容,如果未能解决你的问题,请参考以下文章

tomcat 没有在内存不足错误时生成 hprof 文件

堆内存溢出排查

使用 VisualVm 分析堆转储时出现内存不足错误

eclipse内存分析工具导入android内存文件hprof报错:Unknown HPROF Version

eclipse内存分析工具导入android内存文件hprof报错:Unknown HPROF Version

hprof 文件查看