被隐藏了,关于Android内存泄漏的那些事

Android-内存泄漏处理(2) 其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。当然我也为你们整理好了百度、阿里、腾讯、字节跳动等等互联网超级大厂的历年面试真题集锦。这也是我这些年来养成的习惯,一定要学会把好的东西,归纳整理,然后系统的消化吸收,这样才能极大的提高学习效率和成长进阶。碎片、零散化的东西,我觉得最没有价值的。就好比你给我一张扑克牌,我只会觉得它是一张废纸,但如果你给我一副扑克牌,它便有了它的价值。 阅读详情

概念
内存泄漏(Leak):当一个无用的对象仍然被其它对象所持有引用,从而造成该对象无法被系统回收,以致该对象在堆中所占用的内存单元无法被释放而造成内存空间浪费。最坏的情况下,内存泄漏会导致内存溢出。

内存溢出(OutIfMemoryError,OOM):为了允许多进程,Android为每个应用程序分配的堆大小设置了硬性限制。确切的堆大小限制根据设备有多少内存总量而有所不同。如果你的应用程序使用的内存已达到该限制并尝试分配更多内存时,系统就会抛出OutOfMemoryError。

原因
单例模式下使用Activity作为Context
错误代码

public class TestManager {

private static TestManager manager;
private Context context;

private TestManager(Context context) {
this.context = context;
    }
public static TestManager getInstance(Context context) {
if (manager == null) {
            manager = new TestManager(context);
        }
return manager;
    }
}
单例模式的静态特性导致它的对象的生命周期是和应用一样的,这种写法单例模式持有这个Activity的引用,导致Activity无法被释放,造成内存泄漏。
正确代码

public static TestManager getInstanceSafe(Context context) {
if (manager == null) {
            manager = new TestManager(context.getApplicationContext());
        }
return manager;
    }

通过context.getApplicationContext()使用ApplicationContext作为Context传入,才能避免内存泄漏。如果一定要使用Activity的话,要使用弱引用。
需要手动关闭的资源没有关闭
如IO流需要调用close()方法进行关闭,广播需要取消注册等,而且需要在finally块中执行,保证无论如何都会关闭。

Handler使用不当
错误代码

public class MainActivity extends AppCompatActivity {
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//do something
        }
    };
private void loadData(){
//do request
        Message message = Message.obtain();
        mHandler.sendMessage(message);
    }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        loadData();
    }
}

这种情况mHandler是Handler的非静态匿名内部类的实例,持有外部类Activity的引用,如果这个Activity退出时消息队列中还有未处理的消息或者正在处理的消息,那么这时候Message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏。
正确代码

public class MainActivity extends AppCompatActivity {
private MyHandler mHandler = new MyHandler(this);
private void loadData() {
//do request
        Message message = Message.obtain();
        mHandler.sendMessage(message);
    }
private static class MyHandler extends Handler {
private WeakReference<Context> reference;
public MyHandler(Context context) {
            reference = new WeakReference<Context>(context);
        }
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
            MainActivity mainActivity = (MainActivity) reference.get();
if (mainActivity != null) {
//do something to update UI via mainActivity
            }
        }
    }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        loadData();
    }
}

创建一个静态Handler内部类,然后对Handler持有的对象使用弱引用。(弱引用,即在引用对象的同时仍然允许通过垃圾回收来回收该对象。)同时,对于还未处理完的消息,应在onDestroy()中通过removeCallbacksAndMessages(null)移除。

@Override
protected void onDestroy() {
super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
}
** AsyncTask使用不当**
AsyncTask造成内存泄漏的情况和Handler一样,这里不多说,直接上代码。
错误代码

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
new MyAscnyTask().execute();
    }

class MyAscnyTask extends AsyncTask<Void, Integer, String>{
@Override
protected String doInBackground(Void... params) {
try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
return "";
        }
    }
}

MyAsyncTask 是一个非静态内部类,在 doInbackground() 方法中执行耗时操作。如果在耗时操作结束之前,Activity 被销毁了,这时候因为 MyAsyncTask 持有 Activity 的强引用,便会导致 Activity 的内存无法被回收,产生内存泄露。
解决:使用静态内部类+弱引用,类似Handler 。
线程引发的内存泄漏
线程生命周期的不可控性导致很容易引发内存泄漏。一段经典的代码:
错误代码

new Thread(new Runnable() {
@Override
public void run() {
try {
                    Thread.sleep(50000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

new 出一个匿名的 Thread,进行耗时的操作,线程隐式持有Activity的引用,Thread 中的耗时操作没有结束时,Activity也不会被销毁,导致内存泄漏。
解决:使用静态内部类+弱引用。
集合造成内存泄漏
错误代码

static List<Object> objectList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Object obj = new Object();
       objectList.add(obj);
       obj = null;
    }

我们将一个对象添加到 List 等集合中,这个集合就会持有该对象的引用。这段代码中的objectList是静态变量,生命周期和app一致,它持有集合中对象的引用,导致这些对象无法被释放,造成内存泄漏。
解决:

objectList.clear();
objectList = null;

objectList.clear();将集合中的所有对象都释放了,但是list对象还是存在。
objectList = null;将集合置空,为集合分配的空间也会回收。

WebView造成内存泄漏
WebView 已经为我们提供了销毁的方法:destroy() ,但有时候并不能将 WebView 销毁释放内存。因为 WebView 中 Callback 也会持有 Activity 对象,从而造成无法释放内存。所以在销毁 WebView 之前应该将 WebView 从父容器中移除,再销毁。

正确代码


@Override
protected void onDestroy() {
super.onDestroy();
// 先从父控件中移除WebView
    mWebViewContainer.removeView(mWebView);
    mWebView.stopLoading();
    mWebView.getSettings().setJavaScriptEnabled(false);
    mWebView.clearHistory();
    mWebView.removeAllViews();
    mWebView.destroy();
}
Android应用按钮自动隐藏功能实现与优化 在Android应用开发中,UI交互优化是提升用户体验的关键技术之一。通过View动画和触摸事件处理机制,开发者可以实现控件动态显隐效果,这种技术广泛应用于视频播放器、电子书阅读器等需要最大化屏幕利用率的场景。按钮自动隐藏功能基于Handler定时器和属性动画实现,其核心原理是在用户无操作时自动隐藏非关键UI元素,触摸屏幕时重新显示。这种方案既能保持功能完整性,又能创造更沉浸的视觉体验。从工程实践角度看,需要注意处理生命周期管理、内存泄漏预防等常见问题,同时根据不同设备尺寸和用户场景进行智能延迟时间调整。通 阅读详情

相关推荐

安卓后台服务开发与自启动隐藏图标实践

Android后台服务(Service)是一种允许应用在后台执行长时间运行操作而不提供用户界面的组件。Service是Android开发中极为重要的部分,它可以执行各种后台任务,如播放音乐、进行网络操作等,即便应用界面不处于活跃状态。Android系统提供了一套完整的权限管理机制,以保障用户隐私和设备安全。每一个应用都有自己的用户ID和Linux用户ID,因此默认情况下,应用只能访问自己的文件和数据。

weixin_30632267的博客 1341

android Handler避免内存泄露handler.removeCallbacksAndMessages(null)的使用

今天,简单讲讲android如何使用 handler.removeCallbacksAndMessages(null)。 这个其实很简单,之前我也写了一篇博客将关于handler.removeMessages(int what)的使用,那个是删除handler的特定的消息,而如果需要删除handler所有的消息和回调函数呢?那就需要使用handler.removeCallbacksAndMessa...

qq_26317325的博客 1556

计算机考研408复试题汇总

TCP连接是全双工的,两端都可以先挥手 其中一端完成数据发送任务后,发送一个FIN包来终止,另一端针对这个FIN包回复确认包, 直到另一端也发送请求终止数据包FIN,另一端作出确认应答,并且还要发送一个ACK=1表示确认号有效,如果没有收到这个就可以进行重传.

ca1m4n的博客 1万+

[android小知识]removeCallbacks与postDelayed的恩怨史(removeCallbacks所谓的无效, View和Handler 的postDelayed)...

常见的.postDelayed(runnable, time)方法就是常见的延迟处理的方法之一,postDelayed(mRun,time);当想要需要取消的时候,调用removeCallbacks(mRun);即可,就可以取消postDelayed的方法里面的runnable,当然如果里面runnable已经执行了,那就不可能撤回或者中止了。 http://blog.youkuaiyun.com/blue...

bluewindtalker的专栏 1508

Unity AssetBundle 之 (入门)简单的资源打包成AB包的方法

Unity AssetBundle 之 (入门)简单的资源打包成AB包的方法 目录 Unity AssetBundle 之 (入门)简单的资源打包成AB包的方法 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、实现步骤 六、关键代码 一、简单介绍 Unity中的一些基础知识点。 本节介绍,Asset Bundle 在 Unity中的使用,入门第一篇,如何AssetBundle标记,如何打包成AssetBundle的操作方法,有不对的地方欢迎指正。...

仙魁XAN 1万+

双向全桥隔离dc-dc变换器(DAB)

在全功率范围内,零电压开通优化调制方法能够实现双向全桥隔离dc-dc变换器所有开关的零电压开通,来提升变换器的效率,但其调制模式不连续。当变换器两端电压不匹配时,变换器的电流应力和回流功率将增加,软开关范围将变窄,变换器的效率显著降低。在轻载时,这两种电流优化调制方法采用相同的调制模式;在重载时,最小电流有效值调制方法具有两种调制模式,而最小电流应力调制方法只有一种。双向全桥隔离dc-dc变换器(DAB)和Buck/Boost不同,该变换器通过交流电感进行功率传输,其调制和控制不适合直接借鉴已有的研究。

m0_59329334的博客 3525

Android 定时器实现的几种方式和removeCallbacks失效问题详解

实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用Handler + Runnable的方式 Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { //你要做的事 //...... System.out.print...

runfeel 629

Xilinx PL端DP显示接口开发实战(一)——环境搭建与硬件选型

本文详细介绍了Xilinx PL端DP显示接口开发的环境搭建与硬件选型实战经验。从Vivado和Vitis 2021.1版本的软件安装要点,到DP141和MCDP6000芯片的选型建议,再到DP1.4接口的RX/TX方向开发关键点,为开发者提供了全面的技术指导。文章还分享了IP核配置、BD原理图设计以及常见问题排查的实用技巧,帮助开发者高效完成Xilinx DP接口开发项目。

weixin_29250573的博客 171

我的Android进阶之旅------>Handlerr.removeCallbacksAndMessages(null)的作用

今天都到一段代码,在onDestroy()方法中,使用了下面的代码: mHandler.removeCallbacksAndMessages(null); 一开始我完全看不懂,我为什么参数是null,如果是null还需要移除什么Callbacks和Messages。后来察看官方文档有...

weixin_33716941的博客 491

硬核反坑!YOLOv5训练避坑指南:根治梯度消失、不收敛、检测漏框三大核心问题(附实战代码+调优清单)

数据是基础,超参数是关键,模型是工具,训练策略是保障。梯度消失、不收敛、检测漏框这三大问题,本质上都是“数据-模型-训练”不匹配的结果。梯度消失/爆炸:优先调整学习率策略+梯度裁剪,其次优化模型结构;训练不收敛:优先清洗数据集,其次调优超参数,最后检查配置文件;检测漏框:优先重新聚类锚框,其次增强浅层特征,最后调整推理参数。YOLOv5训练的最高境界,不是调参,而是让数据、模型、训练策略三者完美匹配。按本文的方法反坑,你的YOLOv5训练一定能一次成功!🚀。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 232

dolphinscheduler集群服务一键安装启动实现流程剖析

通过以上分析我们基本梳理清楚了整个dolphinscheduler项目的一键安装启动逻辑, 我们现在在通过一张图正好理一下整个实现流程。关于一键停止集群服务及一件查询集群各个角色服务实例运行状态的实现也都在stop-all.sh/status-all.sh及dolphinscheduler-daemon.sh这三个脚本中, 有兴趣自行研究。写这篇文章的核心目的不仅在于给大家分享如何优秀的开源项目的一键安装部署的实现过程。

最爱嫣夜来 1207

Android中Handler.removeCallbacksAndMessages(null)的作用

众所周知,在Android开发中会大量使用到Handler。但是,由于与activity生命周期不一致,当一个Activity被销毁时,如果Handler对象有Message在排队,则无法释放,进而导致Activity对象无法释放,造成内存溢出。   解决的方法是在Activity被销毁时,在onDestroy()中调用Handler的removeCallbacksAndMessages()方法

JustDoItToday的专栏 7442

使用virtuoso gds转lef操作方法

2) 然后,需要创建Pin,这里Pin的概念不同于label/text,是有实际金属的,二者的区别类似于pr中的port和terminal。1) 首先,需要画prBoundary,这个用drawing层的prBoundary画是不行的,不过建议pr阶段就把prBoundary转到gds里,在virtuoso layout中画prBoundary就比较容易。另外,用Create - Create Pin也可以创建pin,更适用于PG pin,操作时先给pg shape打label,最好放正中间。

m0_61544122的博客 1376

gtk 控件内存回收_被隐藏了,关于Android内存泄漏的那些事

概念内存泄漏(Leak):当一个无用的对象仍然被其它对象所持有引用,从而造成该对象无法被系统回收,以致该对象在堆中所占用的内存单元无法被释放而造成内存空间浪费。最坏的情况下,内存泄漏会导致内存溢出。内存溢出(OutIfMemoryError,OOM):为了允许多进程,Android为每个应用程序分配的堆大小设置了硬性限制。确切的堆大小限制根据设备有多少内存总量而有所不同。如果你的应用程序使用的内存...

weixin_39633774的博客 216

Apache Jena SPARQL 查询完全指南:入门与实战案例

本文介绍了使用Apache Jena执行SPARQL查询的完整指南。SPARQL是用于RDF数据的标准查询语言,在知识图谱领域地位相当于SQL。教程从基础开始,涵盖创建模型、加载数据以及执行各种查询类型。特别强调了WHERE子句中的图模式匹配机制,通过Mermaid图直观展示数据图与查询图的匹配过程。文章还对比了变量命名规范(?和$前缀),解释了SPARQL引擎如何通过变量绑定实现数据检索。通过Hello World示例演示了完整查询流程,为开发者提供了SPARQL的实用入门指导。

Lincoln 的专栏 1371

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Android 开发中如何避免内存泄漏:让您的应用稳如老狗

在 Android 开发过程中,内存泄漏可是个让人头疼的问题。它就像隐藏在代码中的 “定时炸弹”,随时可能让您的应用崩溃,让用户满意度直线下降。今天,就让我们一起探讨一下内存泄漏的那些事儿,让您从此告别内存泄漏的烦恼。

qixiyang9412的博客 1691

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Android实现定时隐藏View(附带源码)

Android实现定时隐藏View(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1064

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

android利用timer隐藏组件,android实现控件数秒隐藏

安卓如何让控件延迟数秒隐藏一.使用Timer1、加一个Timer,设置2000表示2秒后执行Tick事件2、因为你只需要执行一次,所以在一次Tick之后,注销Tick事件,停止Timer代码如下:Label lbl = new Label();Timer timer = new Timer();timer.Interval = 2000;timer.Tick += (timer_Tick);tim...

weixin_39947396的博客 368

Android 开发之内存泄漏

好啦,关于 Android 开发中的内存泄漏就讲到这儿啦。虽然内存泄漏这个 “小怪兽” 很狡猾,但只要我们掌握了它的套路,再加上合适的工具和正确的代码编写习惯,就一定能把它收拾得服服帖帖,让我们的 App 跑得又快又稳。希望我的这些经验能帮到大家,要是你在开发中也遇到过内存泄漏的问题,欢迎在评论区分享你的解决方法,咱们一起交流进步!

qq_35905005的博客 594

利用MAT进行内存泄漏分析

前言 对于程序员来说码代码容易,保证代码的稳定性很难。有时候写完一个功能可能只需要一天时间,但是这个功能隐藏的bug导致的线上问题排查可能需要一周或者更长时间。因此,拥有良好的代码结构和编码规范是一个程序员应该长期坚持并为之奋斗的一个目标。但是,百密也难免一疏,没有百分之百没有问题的代码,在产品上线前,我们需要对自己的代码进行充分的自测,发现问题解决问题,保证自己产品的稳定性并减少对用户的

大雀儿飞飞的专栏 4万+

android实现控件数秒隐藏

安卓如何让控件延迟数秒隐藏 一.使用Timer 1、加一个Timer,设置2000表示2秒后执行Tick事件 2、因为你只需要执行一次,所以在一次Tick之后,注销Tick事件,停止Timer 代码如下: Label lbl = new Label(); Timer timer = new Timer(); timer.Interval = 2000; timer.Tick += (timer_T...

bs19980706的博客 1410

Android知识 :Android 的UI、dialog没有显示时isShowing方法还是为true、Android内存泄漏应用程序会崩溃吗?Android列表notifyDataSetChang

【代码】Android知识 9月14日。Android的UI、dialog、Android内存泄漏应用程序会崩溃吗?Android列表notifyDataSetChanged用法??lambda表达式??Android隐藏标题栏的四种方法??关于Activity的生命周期,面试题涉及了各个生命周期方法的执行顺序和作用,例如onCreate、onStart、onResume、onPause、onStop、onDestroy等。对于面试者而言,理解和熟悉Activity的生命周期对于开发稳定、响应式的应用程序至

qq_46906413的博客 1277

移动端(Android、iOS)内存泄漏检测方法

移动端(Android、iOS)内存泄漏检测方法

q345911572的博客 2595

Android Native内存泄漏诊断

Android Native内存泄漏诊断1、基础诊断方法特点:操作简单,但只能判断是否有泄漏,但需使用者自行判断泄漏在哪里命令行方式adb shell dumpsys meminfo vStudio.Android.Camera360 -d结果如图: Android Studio1、选中机器和进程,点击箭头所指按钮 2、点击Memory Usage 示例例如,若需检测取景页是否有内存泄漏 先

yellowcath的专栏 9931

Android内存泄漏的检测流程、捕捉以及分析

Android内存泄漏的检测流程、捕捉以及分析简述:一个APP的性能,重度关乎着用户体验,而关于性能检测的一个重要方面,就是内存泄漏,通常内存泄漏的隐藏性质比较强,不同于异常导致的程序Crash,在异常导致的Crash中,我们能够及时的发现程序问题的存在,并通过log日志定位到问题所在的具体位置,然后及时进行解决,而内存泄漏则不同,在APP中存在内存泄漏的情况下,用户在低频率短时间的使用中,并不能察

李苏哲的博客 3万+

安卓优化二(内存泄漏的处理)

2

qq_37961962的博客 223
上一篇: 三分钟,带你了解Android音`视频开发进阶
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值