Android——内存泄漏及OOM整理

Android 性能分析(一)—— 概要篇 最近需要对app进行性能分析,一开始的时候,都是根据网上的各种文章参考,但是很多都是只是介绍概念,没有介绍使用什么工具以及什么样效果需要进行优化,因为我们对app优化肯定是要达到什么样的效果,必须给出一篇优化文档的,我们目前是什么样的效果,经过优化过后达到什么样的预期效果,这样领导才会同意你去安排开发和测试抽出时间去进行优化,并且各个模块能达到什么样的效果都是需要进行统计的,这都是需要时间去安排的,这种就很可能导致产品提的需求和优化时间冲突了,需求就要延期,开发领导去和产品领导扯皮,一堆麻烦事,因此我们必须 阅读详情

内存泄漏

内存泄漏是指对象已经没有被应用程序使用,但是垃圾回收器没办法移除它们,因为还在被引用着。

下面是一些常见的Activity内存泄漏

静态变量引用Activity

静态变量引用Activty对象时,会导致Activty对象所占内存内漏。

原因:静态变量是驻扎在JVM的方法区,因此,静态变量引用的对象是不会被GC回收的,因为它们所引用的对象本身就是GC ROOT,即最终导致Activity对象不被回收,从而也就造成内存泄漏。

常见的错误用法:

将Context或Activity赋值给某个静态变量

解决:

  • 去掉 static 关键字,使用别的方法来实现想要的功能。
  • 在 onDestroy 方法中置空 Activity 静态引用
  • 也可以使用到软引用解决,确保在 Activity 销毁时,垃圾回收机制可以将其回收。

static间接修饰Activity

有时,当一个Activity经常启动,但是对应的View读取非常耗时,我们可以通过静态View变量来保持对该Activity的rootView引用。这样就可以不用每次启动Activity都去读取并渲染View了。这确实是一个提高Activity启动速度的好方法!但是要注意,一旦View attach到我们的Window上,就会持有一个Context(即Activity)的引用。而我们的View有事一个静态变量,所以导致Activity不被回收。当然了,也不是说不能使用静态View,但是在使用静态View时,需要确保在资源回收时,将静态View detach掉。

常见问题

public class LoadingDialog extends Dialog {
    private static LoadingDialog mDialog;
    private TextView mText;
}

这里 static 虽然没有直接修饰 TextView(拥有 Context 引用),但是修饰了 mDialog 成员变量,mDialog 是 一个 LoadingDialog 对象, LoadingDialog 对象 包含一个 TextView 类型的成员变量,所以 mText 变量的生命周期也是全局的,和应用一样。这样,mText 持有的 Context 对象销毁时,没有 GC 回收,导致内存泄露。

解决:

  • 不使用static修饰
  • 在适当的地方置空 mDialog

单例引用Context

public class AppManager {
    private static AppManager instance;
    private Context context;

    private AppManager(Context context) {
        this.context = context;
    }

    public static AppManager getInstance(Context context) {
        if (instance == null) {
            instance = new AppManager(context);
        }
        return instance;
    }
} 

AppManager是一个单例类,他需要Context作为成员变量,Context 如果是 Activity Context 的话,必然会引起内存泄漏。

解决

  • 使用 Applicaion Context 代替 Activity Context
  • 在调用的地方使用弱引用

匿名内部类执行耗时任务

public class MainActivity extends Activity {  
    @Override
    protected void onCreate(Bundle savedInstanceState) {    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        test();
    }  
    public void test() {    
        new Thread(new Runnable() {     
            @Override
            public void run() {        
                while (true) {          
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
} 

原因

  • 非静态内部类或匿名类会拥有所在外部类的引用,new Thread是匿名内部类,它一直在执行当Activity消耗后,该匿名内部类还在执行任务,导致外部的Activity不能回收。

解决

  • 静态匿名内部类,使用static修饰
    public static void test() {
        new Thread(new Runnable() {     
                @Override
                public void run() {        
                    while (true) {          
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
    } 
    

非静态内部类

如果一个变量,既是静态变量,而且是非静态的内部类对象,那么也会造成内存泄漏。

public class LeakActivity extends AppCompatActivity {
    
    private static Hello sHello;
    
    @Override    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);
        
        sHello = new Hello();
    }
    
    public class Hello {}
}

这里我们定义的 Hello 虽然是空的,但它是一个非静态的内部类,所以它必然会持有外部类即 LeakActivity.this 引用,导致 sHello 这个静态变量一直持有这个 Activity,Activity 无法被回收。

Handler引起的内存泄漏

这与非静态匿名内部类执行耗时任务一样,错误代码如下。

public class MainActivity extends Activity {
    private final Handler mLeakyHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // ...
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mLeakyHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                // ...
            }
        }, 1000 * 60 * 10);
        finish();
    }
} 

在活动中发送了一个延时十分钟消息的message,handler会将消息放入MessageQueue里面。当活动被finish()时,Message还会继续存在于主线程,Handler是非静态内部类,会持有该活动的引用,所以此时finish()掉的活动就不会回收。

解决方法:

自定义静态Handler

public class MainActivity extends Activity {

    private final MyHandler mHandler = new MyHandler(this);

    private static final Runnable mRunnable = new Runnable() {
        @Override
        public void run() { /* ... */ }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mHandler.postDelayed(mRunnable, 1000 * 60 * 10);
        finish();
    }

    private static class MyHandler extends Handler {
        private final WeakReference<MainActivity> mActivityReference;

        public MyHandler(MainActivity activity) {
            mActivityReference = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = mActivityReference.get();
            if (activity != null) {
                // ...
            }
        }
    }
} 

解释:

  • 声明一个静态的MyHandler类,他不会隐式的持有MainActivity的引用
  • 内部利用弱引用获取外部类的引用,若Activity回收,弱引用不会影响Activity的回收

资源对象没有关闭

资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄漏。

OOM

OOM,全称Out Of Memory,当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个Error。

原因

  • 内存泄漏导致,频繁的内存泄漏将会引发内存溢出。
  • 占用内存较多的对象,保存了多个耗用内存较多的对象(如Bitmap),加载超大的图片。

加载图片OOM处理

  • 等比例缩小图片
    使用setImageBitmap或setImageResource或BitmapFactory.decodeResource设置大图时,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
    public static Bitmap scaleImage(Bitmap bitmap, int newWidth, int newHeight) {
            if (bitmap == null) {
                return null;
            }
            float scaleWidth = (float) newWidth / bitmap.getWidth();
            float scaleHeight = (float) newHeight / bitmap.getHeight();
            Matrix matrix = new Matrix();
            matrix.postScale(scaleWidth, scaleHeight);
            return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        }
    
  • 对图片采用软引用,及时地进行recycle()操作。
    虽然系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制。因此,在用完Bitmap时要及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。
    SoftReference<Bitmap> bitmap;
        bitmap = new SoftReference<>(pBitmap);
        if(bitmap != null){
            if(bitmap.get() != null && !bitmap.get().isRecycled()){
                bitmap.get().recycle();
                bitmap = null;
            }
        }
    

其他OOM可使用LeakCanary检测是否发生了内存泄漏。


对于图片加载还有种情况,就是单个图片非常巨大,并且还不允许压缩。

那么对于这种需求,该如何做呢?

首先不压缩,按照原图尺寸加载,那么屏幕肯定是不够大的,并且考虑到内存的情况,不可能一次性整图加载到内存中,所以肯定是局部加载,那么就需要用到一个类:BitmapRegionDecoder ,这个类提供了decodeRegion()方法来显示指定的区域。

大意了,又是 OOM ,Android 内存监控一定要注意这几点! 前言 性能优化是一个老生常谈的问题,也一直是Android中高级攻城狮进阶和深入的方向。 在性能优化的各种问题中,内存泄漏一直占有较重要的地位。内存泄漏的积累会造成内存溢出,进而导致程序崩溃,出现OOM问题。 针对这个问题,我们需要在上线前进行检测同时也要能够实现线上的监控。 方案一:线下性能监控 Android Studio自身提供的MAT等工具分析内存泄漏比较耗时,因而诞生了LeakCanary——这也是现在寻找内存泄漏问题最常用的工具。 LeakCanary 这个工具非常简单,依赖 Lea 阅读详情

相关推荐

Probe:Android线上OOM问题定位组件,看完这篇彻底明白了

系统源码文件:/art/runtime/thread.cc抛出时的错误信息:或者这是创建线程时抛出的OOM错误,且有多种错误信息。源码这里不展开详述了,下面是根据源码整理的Android中创建线程的步骤,其中两个关键节点是创建JNIEnv结构体和创建线程,而这两步均有可能抛出OOM。

2401_84149882的博客 1141

Android内存优化/内存泄漏排查

内存优化/内存泄漏排查

木易匕禾页的博客 1263

Android BitmapRegionDecoder加载超大图片

Android BitmapRegionDecoder加载超大图片和使用Glide缓存

Android OOM(OutOfMemory)内存溢出和内存泄漏问题及解决方案

OOM(OutOfMemory)内存溢出 OOM指申请的内存没有足够,导致出现OutOfMemory的一种现象、 查看内容限制的方式如下,可以使用adb命令如下图 OOM产生的几大因素 内存泄漏 长期的内存泄漏最终会导致OOM内存溢出 常见的内存泄漏原因如下: 1.单例模式传activityContext会造成内存泄漏,传applicaionContext可以避免造成内存泄漏 2.非静态内部类创建静态实例会造成内存泄漏 3.Handler使用延时方式调用会造成内存泄漏,可以..

qq_35298279的博客 1100

PCIE配置和地址空间

来源:https://www.jianshu.com/p/574e9a2cbc4e 每个PCIe设备,有这么一段空间,Host软件可以读取它获得该设备的一些信息,也可以通过它来配置该设备,这段空间就叫做PCIe的配置空间。不同于每个设备的其它空间,PCIe设备的配置空间是协议规定好的,哪个地方放什么内容,都是有定义的。PCI或者PCI-X时代就有配置空间的概念,那时的配置空间如下: 图6.1 整个配置空间就是一系列寄存器的集合,其中Type 0是Endpoint的配置,Type 1是Brid.

qq_28643619的博客 4059

【测试】echo发送和接收TCP/UDP数据包|shell 发送TCP/UDP数据包

目录 通过/dev/tcp、/dev/udp shell给tcp或udp服务发送16进制报文指令 通过/dev/tcp、/dev/udp (https://blog.youkuaiyun.com/u010039418/article/details/86251470) 通过/dev/tcp、/dev/udp可以直接在shell脚本中发起tcp、udp连接,方便又高效,平时用于测试啥的还是挺方便的。 直接发送 格式 /dev/udp/ip/port 比如要向本地10001端口发送数据,可以使用 ec.

我的笔记本 1万+

Android优化总结

目录介绍 1.OOM和崩溃优化 1.1 OOM优化 1.2 ANR优化 1.3 Crash优化 2.内存泄漏优化 2.0 动画资源未释放 2.1 错误使用单利 2.2 错误使用静态变量 2.3 handler内存泄漏 2.4 线程造成内存泄漏 2.5 非静态内部类 2.6 未移除监听 2.7 持有activity引用 2.8 资源未关闭 2.9 其他原因 3.布局优化 3.1 in...

weixin_34184561的博客 542

SNN系列|编码篇(2)时序编码

Tempotral Coding 选择编码方法是要根据编码对象以及模型如何处理编码信息进行选择,如下是一种时序信息的编码对比: Threshold-based encoding 又称为tempotral contrast,该方法可以用于编解码一段序列,当差值超过阈值时发放脉冲,阈值是根据编码的序列自适应变化的。 使用该编码方法时,实值序列最好是沿时间变化的,因为在根据差分决定是否发放脉冲后,脉冲的顺序与差分顺序有关。 Time-to-first spike coding 该编码方法将信息用神经元首次

Tianlong Lee的博客 1万+

Android开发常见的Activity中内存泄漏及解决办法

上一篇文章楼主提到由Context引发的内存泄漏,在这一篇文章里,我们来谈谈Android开发中常见的Activity内存泄漏及解决办法。本文将会以“为什么”“怎么解决”的方式来介绍这几种内存泄漏。 在开篇之前,先来了解一下什么是内存泄漏。什么是内存泄漏? 内存泄漏是当程序不再使用到的内存时,释放内存失败而产生了无用的内存消耗。内存泄漏并不是指物理上的内存消失,这里的内存泄漏是值由程序分配的内

碎格子 2万+

2、TCGA数据处理(差异分析前处理)

注意:1、是R语言中用于读取文本文件并创建数据框的函数。它可以从文本文件中读取数据并将其存储为数据框的形式,每一列代表一个变量,每一行代表一个观察值。2、括号要成对,不能少了;3、file = 'TCGA-LIHC.htseq_counts.tsv'引号可以是单或双引号,建议单;4、逗号主要中英文,都是用英文模式才没错;5、.tsv文件类型必须要有,不能删除,否则读不进来;6、上面代码将TCGA-LIHC.htseq_counts.tsv文件读入并赋值给count1。

PLW_12的博客 2667

1.2 重叠因子:双重指数移动平均(Double Exponential Moving Average, DEMA)概念与Python实战

双重指数移动平均(Double Exponential Moving Average, DEMA)是一种改进的移动平均线指标,由Patrick Mulloy在1994年开发。相比传统的指数移动平均线(EMA),DEMA通过减少滞后性来提供更快的市场反应。它通过两次计算EMA并进行特殊组合来实现这一目标,可以在保持平滑性的同时减少滞后。

Kewin的博客 2167

OOM

Memory Analysis for Android Applications http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html Avoiding memory leaks http://android-developers.blogspot.com/2009/01/a

hexwin的专栏 438

SAP-ABAP:SAP数据库视图的创建图文详解

在“短文本”字段中输入视图的描述。在“表/视图”字段中输入要基于的表名。如果视图基于多个表,可以在这里输入主表。点击“表/视图字段”按钮,选择要包含在视图中的字段。如果视图基于多个表,点击“关系”按钮来定义表之间的连接条件。在弹出的窗口中,选择要连接的表,并定义连接条件(例如。

baidu_35680696的博客 973

【Android】内存分析

Memory Analysis for Android Applications http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html Avoiding memory leaks http://android-developers.blogspot.com/2009/01/a

YING 1204

把 ST03 的历史数据留得更久:ABAP Workload 统计保留期设置、原理与落地避坑指南

SAP ST03性能数据保留期配置指南 ST03/ST03N是SAP系统性能分析的核心工具,但默认数据保留期通常较短(3个月左右),难以满足跨季度对比、年度规划等需求。本文详细解析了ST03数据保留期的配置方法及注意事项: 数据存储机制:性能数据存储在监控库中,通过定期重组作业清理过期数据 配置路径:7.0+系统在"Workload Collector Database→Reorganization→Control"中按Profile分别设置 关键限制:保留期最大值建议不超过99,否则可

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 218

【中国大学生计算机设计大赛信息可视化赛道】国奖项目深入剖析—中国古代奇异怪兽移动端可视化应用项目

【中国大学生计算机设计大赛信息可视化赛道】国奖项目深入剖析—中国古代奇异怪兽移动端可视化应用项目 注:本文主要目的是对于往年国奖项目案例-可视化项目的深入剖析讲解,对源码、项目特点、要点、特色继续深入分析。帮助大家学习技术,掌握规律。

一键难忘的博客 3729

弱引用WeakReference

WeakReference mToast = null; Toast toast; toast = Toast.makeText(mActivity, R.string.empty, Toast.LENGTH_SHORT); mToast = new WeakReference(toast); toast.show();

学习点滴的专栏 576

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

android路由器,Kotlin可能带来的一个深坑,年薪50W

金九银十,给大家整理了月薪20K的Android面试题必问集锦,希望让大家查漏补缺,最后祝大家都能在金九银十找到一份不错的工作! 阿里面试题 说下你所知道的设计模式与使用场景 a.建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 使用场景比如最常见的AlertDialog,拿我们开发过程中举例,比如Camera开发过程中,可能需要设置一个初始化的相机配置,设置摄像头方向,闪光灯开闭,成像质量等等,这种场景下就可以使用建造者模式 装饰者模式:动态的给一个对象添加一些.

m0_56175058的博客 160

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

【性能优化】安卓性能优化之内存优化

安卓内存优化小结

weixin_41802023的博客 1680

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Android OOM 问题整理

一、什么是内存溢出(OOM)        内存泄露是指程序在运行过程中动态申请的内存空间不再使用后没有及时释放,从而很可能导致应用程序内存无线增长。更广义的内存泄露包括未对系统的资源的及时释放,比如句柄等。内存溢出即用户在对其数据缓冲区操作时,超过了其缓冲区的边界;尤其是对缓冲区写操作时,缓冲区的溢出很可能导致程序的异常。        因为android系统的app的每个进程或者每个虚

hehao424的博客 377

android内存泄漏 OOM查找总结

本篇来自 08_carmelo 对 Androidandroid内存泄漏的整理和总结 08_carmelo 的博客地址:https://www.jianshu.com/u/b8dad3885e05先通俗理解下内存泄漏,内存溢出,OOM,GC回收这几个概念。把app的堆内存空间想成了一个杯子,内存就是里面的水。当你的app启动后,系统会分配给app一个堆空间,起始不会很大比如是32M(根据你的app...

zyx709401的博客 863

如何理解和避免OOM

理解和避免 OutOfMemoryError 需要综合考虑多个方面,包括内存泄漏检测和修复、优化大对象分配、处理内存碎片化和资源管理等。通过采用一些最佳实践和使用合适的工具,可以有效地降低 OOM 的风险,提高应用程序的稳定性和性能。在开发过程中,要时刻关注内存使用情况,并进行及时的优化和调整,以确保应用程序在各种情况下都能正常运行。

challenge51all的专栏 915

Android之 内存泄漏问题检测和解决

内存泄漏问题检测和解决

qq_29848853的博客 3055

Android | 关于 OOM 的那些事

Android 系统对每个app都会有一个最大的内存限制,如果超出这个限制,就会抛出 OOM,也就是Out Of Memory。本质上是抛出的一个异常,一般是在内存超出限制之后抛出的。

345丶 1955

Probe:Android线上OOM问题定位组件

总第369篇2019年 第47篇背景配送骑手端App是骑手用于完成配送履约的应用,帮助骑手完成接单、到店、取货及送达,提供各种不同的运力服务,也是整个外卖闭环中的重要节点。由于配送业务的特性,骑手App对于应用稳定性的要求非常高,体现App稳定性的一个重要数据就是Crash率,而在众多Crash中最棘手最难定位的就是OOM问题。对于骑手端App而言,每天骑手都会长时间的使用App进行配送,而在长时...

美团技术团队 7640

Linux oom机制

Linux oom是由于内存泄漏或者内存使用不合理而导致的问题。在讲OOM之前,我们先来了解一下内核内存回收的总体框架。

lzhf1122的博客 2351
上一篇: ARouter——原理分析整理
下一篇: Android——AsyncTask源码分析整理
PdKingLiu
博客等级 码龄9年 89粉丝 92原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值