Android 内存泄漏详解

发布时间:2026/10/1 19:37:41

Android 内存泄漏详解 一、什么是内存泄漏内存泄漏Memory Leak是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放造成系统内存的浪费导致程序运行速度减慢甚至系统崩溃等严重后果。在 Android 中更具体的定义是长生命周期对象持有短生命周期对象的引用导致短生命周期对象无法被垃圾回收器GC回收。二、内存泄漏的危害危害说明OOM 崩溃内存持续增长最终触发OutOfMemoryError应用崩溃卡顿/ANRGC 频繁触发主线程被阻塞界面卡顿甚至 ANR电量消耗后台泄漏导致进程无法被回收持续占用 CPU 和内存用户体验差应用越来越卡需要频繁重启三、导致内存泄漏的常见情况1.静态变量持有 Activity/Context 引用⭐最常见javapublic class Singleton { private static Singleton instance; private Context context; private Singleton(Context context) { this.context context; // ❌ 持有 Activity 引用 } public static Singleton getInstance(Context context) { if (instance null) { instance new Singleton(context); } return instance; } }原因静态变量生命周期 应用生命周期如果传入的是 Activity ContextActivity 销毁后仍被静态引用持有无法回收。解决使用Application Contextcontext.getApplicationContext()。2.非静态内部类 / 匿名内部类持有外部类引用javapublic class MainActivity extends AppCompatActivity { // ❌ 非静态内部类隐式持有外部 Activity 引用 private class MyHandler extends Handler { Override public void handleMessage(Message msg) { // ... } } // ❌ 匿名内部类同样持有 Activity 引用 private Runnable runnable new Runnable() { Override public void run() { // 延迟执行Activity 可能已销毁 } }; }原因非静态内部类会隐式持有外部类的引用。如果内部类有耗时操作如 Handler 延迟消息、AsyncTask、ThreadActivity 销毁时无法被回收。解决使用静态内部类弱引用WeakReference在onDestroy()中移除消息/回调javaprivate static class MyHandler extends Handler { private WeakReferenceMainActivity weakRef; MyHandler(MainActivity activity) { weakRef new WeakReference(activity); } Override public void handleMessage(Message msg) { MainActivity activity weakRef.get(); if (activity ! null) { // 安全使用 } } } Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacksAndMessages(null); // 移除所有消息 }3.Handler 内存泄漏⭐高频考点javapublic class MainActivity extends AppCompatActivity { private Handler handler new Handler(Looper.getMainLooper()) { Override public void handleMessage(Message msg) { // 隐式持有 MainActivity 引用 } }; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler.sendEmptyMessageDelayed(0, 10000); // 10秒后执行 } }原因Message会持有Handler引用Handler持有Activity引用MessageQueue持有Message。如果 Activity 在消息执行前被销毁整条引用链导致 Activity 泄漏。解决静态内部类 WeakReference onDestroy()移除消息。4.资源未关闭java// ❌ 未关闭的资源 Cursor cursor getContentResolver().query(...); // 忘记 cursor.close(); Bitmap bitmap BitmapFactory.decodeResource(...); // 忘记 bitmap.recycle(); // Android 3.0 后 Bitmap 内存由 GC 管理但大 Bitmap 仍建议及时释放 InputStream is ...; // 忘记 is.close();解决使用try-finally或在 Kotlin 中使用use自动关闭。5.监听器未注销javapublic class MainActivity extends AppCompatActivity { Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ❌ 注册后未在 onDestroy 中注销 getSystemService(LocationManager.class) .requestLocationUpdates(..., listener); } }常见场景LocationManager.requestLocationUpdates()未removeUpdates()SensorManager.registerListener()未unregisterListener()BroadcastReceiver动态注册后未unregisterReceiver()EventBus/RxJava订阅后未取消订阅解决在onDestroy()/onStop()中及时注销。6.单例模式持有回调/监听器javapublic class NetworkManager { private static NetworkManager instance; private NetworkCallback callback; public void setCallback(NetworkCallback callback) { this.callback callback; // ❌ 可能持有 Activity 引用 } }解决使用弱引用或在 Activity 销毁时手动置空。7.WebView 内存泄漏java// ❌ 直接在 xml 中声明 WebViewActivity 销毁时 WebView 持有 Activity 引用 WebView android:idid/webview android:layout_widthmatch_parent android:layout_heightmatch_parent /原因WebView 内部逻辑复杂会持有 Activity 引用且不易释放。解决使用独立的进程加载 WebViewandroid:process:web动态添加/移除 WebView销毁时从父布局移除并调用destroy()使用腾讯 X5 内核等第三方方案javaOverride protected void onDestroy() { if (webView ! null) { webView.loadDataWithBaseURL(null, , text/html, utf-8, null); webView.clearHistory(); ((ViewGroup) webView.getParent()).removeView(webView); webView.destroy(); webView null; } super.onDestroy(); }8.集合类泄漏javapublic class CacheManager { // ❌ 静态集合一直增长从未清理 private static ListObject cache new ArrayList(); public void add(Object obj) { cache.add(obj); } // 没有 remove() 或 clear() 机制 }解决使用LruCache等有限容量的缓存或设置过期清理机制。9.属性动画Animator未取消javaObjectAnimator animator ObjectAnimator.ofFloat(view, alpha, 0, 1); animator.setDuration(3000); animator.start(); // ❌ Activity 销毁时未取消动画原因动画会持有 target View 的引用View 持有 Activity 引用。解决在onDestroy()中animator.cancel()。10.系统服务持有 Contextjava// ❌ 错误 InputMethodManager imm (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);某些系统服务如InputMethodManager内部存在已知的内存泄漏 BugAndroid 底层问题。解决使用 Application Context 获取系统服务。11.第三方库使用不当Glide传入 Activity Context 时Glide 会绑定生命周期但如果传入 Application Context 且未手动管理可能泄漏RxJava订阅后未在onDestroy()中dispose()EventBus注册后未unregister()LeakCanary虽然它是检测工具但本身也可能有轻微影响四、内存泄漏检测工具表格工具用途LeakCanarySquare 出品自动检测并展示泄漏引用链开发必备Android Studio Profiler实时查看内存分配Heap Dump 分析MAT (Memory Analyzer Tool)分析 hprof 文件查找支配树和引用链adb shell dumpsys meminfo查看应用内存占用情况五、预防内存泄漏的黄金法则能用 Application Context 就不用 Activity Context静态变量不持有短生命周期对象内部类尽量声明为 static配合 WeakReference有注册就有注销有开启就有关闭耗时操作/延迟任务要考虑生命周期使用 Jetpack 组件ViewModel、Lifecycle、LiveData自动管理生命周期接入 LeakCanary 在开发阶段及时发现六、总结图plain长生命周期对象 ──持有引用──► 短生命周期对象 ↑ │ └───────────────────────────┘ 无法被 GC 回收 内存泄漏
延伸阅读

更多相关文章

2026/9/29 21:51:53

C语言字符串函数进阶:安全版函数 + 错误处理 + 子串查找

适用对象:学过 strcpy / strcat / strcmp 的同学 本章目标:掌握安全版字符串函数 strstr 子串查找 strerror 错误处理引入:strcpy 为什么会让人又爱又恨? 上一章我们学了 strcpy,它简单粗暴,复制速度也快…

2026/10/1 19:36:39

多模态LLM实战:从CLIP视觉编码到信息融合的Wiki技能构建

1. 项目概述:当大语言模型“睁开双眼”最近在折腾一个挺有意思的东西,我把它叫做“多模态 LLM Wiki Skill”。简单来说,就是给一个大型语言模型(LLM)——比如我们熟悉的 Claude 或者 GPT——装上“眼睛”和“耳朵”&am…

2026/9/30 10:47:42

android Handler , Looper , Message , MessageQueue 详解

一、基础Q1:请简述 Handler 机制的工作原理核心回答:Handler 发送消息 → MessageQueue 按时间排序存储 → Looper 无限循环取出 → 回调 Handler 处理。细节:MessageQueue 不是队列,是单向链表,按 when(触…

2026/10/1 19:37:14

AI工程从零起步:数据、微调、RAG与性能优化的全链路指南

"ai-engineering-from-scratch"这个标题,看起来像是一个GitHub仓库名,但它背后其实是所有打算跨进AI工程领域的人都要面对的一份路线图。我已经在这个行业里摸爬滚打了几年,带过的实习生一只手数不过来,他们中最常问我的…

2026/10/1 19:37:14

行列式降阶计算:子式、余子式与代数余子式

对线性代数有点感觉的人,大多是在行列式这一章第一次被“劝退”的。三阶还行,硬算也能算出来;一上四阶,数字一多,展开就成了一团乱麻。而在这一章里,有两个名字听上去特别像的概念会把大部分人绕晕&#xf…

2026/10/1 19:37:14

CODESYS Win V3/RTE 忘记密码恢复:用户管理与配置重置

1. 先把两种仿真设备环境认清:Win V3 和 RTE 各自管什么1.1 CODESYS Control Win V3:最像真实PLC的Windows软仿真CODESYS Control Win V3 是很多人做仿真调试时最先接触的环境。它把一台Windows电脑变成软PLC运行载体,装上之后会在系统服务里…

2026/10/1 19:37:14

UALink技术解析:PCIe生态的外科手术式升级

1. 这不是一场普通的技术分享,而是一条从标准制定到产业落地的完整技术链路UALink、ODCC、云栖大会、服务器测试——这几个词单独拎出来,你可能觉得是零散的技术名词。但把它们串在一起,背后是一条清晰可见的中国数据中心基础设施技术演进主线…

2026/10/1 19:37:14

AI Agent落地全指南:从概念厘清到架构设计与并发实践

前几天康奈尔那篇关于AI Agent的论文又被转到了各个技术群里,评论区吵得不可开交。有人说是给Agent正名了,有人说这不过是个概念梳理,还有人直接甩出一句"看完更不知道怎么落地了"。我完整读完之后,第一反应倒不是论文本…

2026/10/1 19:32:13

多模型工作台配置指南:两行配置接入DeepSeek、Qwen与GLM

1. 多模型工作台的核心思路与选型逻辑把DeepSeek、Qwen、GLM这三个模型塞进同一个工作台,听起来像是个挺唬人的工程,但实际操作下来,真正卡住大多数人的不是模型本身,而是配置层的抽象没做好。我前后折腾过不下五套多模型方案&…

2026/10/1 5:21:14

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/10/1 17:09:46

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 10:48:55

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑