内存泄漏分析二-线程

使用Android Studio分析内存泄漏 Android Studio的Profiler分析内存泄漏 阅读详情

Thread 内存泄露

线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。

1.看一下下面是否存在问题


 
  1. <span style="white-space:pre">    </span>/**  
  2.  *   
  3.  * @version 1.0.0   
  4.  * @author Abay Zhuang <br/>  
  5.  *         Create at 2014-7-17  
  6.  */  
  7. public class ThreadActivity extends Activity {  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.         new MyThread().start();  
  12.     }  
  13.   
  14.     private class MyThread extends Thread {  
  15.         @Override  
  16.         public void run() {  
  17.             super.run();  
  18.             dosomthing();  
  19.         }  
  20.     }  
  21.     private void dosomthing(){  
  22.       
  23.     }  
  24. }  
 <span style="white-space:pre">	</span>/**
	 * 
	 * @version 1.0.0 
	 * @author Abay Zhuang <br/>
	 *		   Create at 2014-7-17
	 */
	public class ThreadActivity extends Activity {
		public void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.activity_main);
			new MyThread().start();
		}
	
		private class MyThread extends Thread {
			@Override
			public void run() {
				super.run();
				dosomthing();
			}
		}
		private void dosomthing(){
		
		}
	}



 这段代码很平常也很简单,是我们经常使用的形式。 
 

真的没有问题吗

我们思考一个问题:假设MyThread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,
一般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。
由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,
MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。   

2.这种线程导致的内存泄露问题应该如何解决呢?

  • 第一、将线程的内部类,改为静态内部类。
  • 第二、在线程内部采用弱引用保存Context引用。 代码如下:

    
       
    1. <span style="white-space:pre">        </span>/**  
    2.          *   
    3.          * @version 1.0.0  
    4.          * @author Abay Zhuang <br/>  
    5.          *         Create at 2014-7-17  
    6.          */  
    7.           
    8.         public class ThreadAvoidActivity extends Activity {  
    9.             public void onCreate(Bundle savedInstanceState) {  
    10.                 super.onCreate(savedInstanceState);  
    11.                 setContentView(R.layout.activity_main);  
    12.                 new MyThread(this).start();  
    13.             }  
    14.           
    15.             private void dosomthing() {  
    16.           
    17.             }  
    18.           
    19.             private static class MyThread extends Thread {  
    20.                 WeakReference<ThreadAvoidActivity> mThreadActivityRef;  
    21.           
    22.                 public MyThread(ThreadAvoidActivity activity) {  
    23.                     mThreadActivityRef = new WeakReference<ThreadAvoidActivity>(  
    24.                             activity);  
    25.                 }  
    26.           
    27.                 @Override  
    28.                 public void run() {  
    29.                     super.run();  
    30.                     if (mThreadActivityRef == null)  
    31.                         return;  
    32.                     if (mThreadActivityRef.get() != null)  
    33.                         mThreadActivityRef.get().dosomthing();  
    34.                     // dosomthing  
    35.                 }  
    36.             }  
    37.         }  
    <span style="white-space:pre">		</span>/**
    		 * 
    		 * @version 1.0.0
    		 * @author Abay Zhuang <br/>
    		 *         Create at 2014-7-17
    		 */
    		
    		public class ThreadAvoidActivity extends Activity {
    			public void onCreate(Bundle savedInstanceState) {
    				super.onCreate(savedInstanceState);
    				setContentView(R.layout.activity_main);
    				new MyThread(this).start();
    			}
    		
    			private void dosomthing() {
    		
    			}
    		
    			private static class MyThread extends Thread {
    				WeakReference<ThreadAvoidActivity> mThreadActivityRef;
    		
    				public MyThread(ThreadAvoidActivity activity) {
    					mThreadActivityRef = new WeakReference<ThreadAvoidActivity>(
    							activity);
    				}
    		
    				@Override
    				public void run() {
    					super.run();
    					if (mThreadActivityRef == null)
    						return;
    					if (mThreadActivityRef.get() != null)
    						mThreadActivityRef.get().dosomthing();
    					// dosomthing
    				}
    			}
    		}


     
     

上面的两个步骤其实是切换两个对象的双向强引用链接

  1. 静态内部类:切断Activity 对于 MyThread的强引用。
  2. 弱引用: 切断MyThread对于Activity 的强引用。

3.AsynTask 内部类会如何呢?

有些人喜欢用Android提供的AsyncTask,但事实上AsyncTask的问题更加严重,
Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,
该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,
因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。

代码如下:

 
  1. /**  
  2.  *   
  3.  * 弱引用  
  4.  * @version 1.0.0   
  5.  * @author Abay Zhuang <br/>  
  6.  *         Create at 2014-7-17  
  7.  */  
  8. public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget>  
  9.     extends AsyncTask<Params, Progress, Result> {  
  10. protected WeakReference<WeakTarget> mTarget;  
  11.   
  12. public WeakAsyncTask(WeakTarget target) {  
  13.     mTarget = new WeakReference<WeakTarget>(target);  
  14. }  
  15.   
  16. @Override  
  17. protected final void onPreExecute() {  
  18.     final WeakTarget target = mTarget.get();  
  19.     if (target != null) {  
  20.         this.onPreExecute(target);  
  21.     }  
  22. }  
  23.   
  24. @Override  
  25. protected final Result doInBackground(Params... params) {  
  26.     final WeakTarget target = mTarget.get();  
  27.     if (target != null) {  
  28.         return this.doInBackground(target, params);  
  29.     } else {  
  30.         return null;  
  31.     }  
  32. }  
  33.   
  34. @Override  
  35. protected final void onPostExecute(Result result) {  
  36.     final WeakTarget target = mTarget.get();  
  37.     if (target != null) {  
  38.         this.onPostExecute(target, result);  
  39.     }  
  40. }  
  41.   
  42. protected void onPreExecute(WeakTarget target) {  
  43.     // Nodefaultaction  
  44. }  
  45.   
  46. protected abstract Result doInBackground(WeakTarget target,  
  47.         Params... params);  
  48.   
  49. protected void onPostExecute(WeakTarget target, Result result) {  
  50.     // Nodefaultaction  
  51. }  
  52. }  

Android Studio 分析内存泄漏 内存分析入门 阅读详情

相关推荐

内存泄漏系列专题分析之二十:camx swap内存泄漏实例分析

本文分析了相机服务进程(camxhal)在老化测试中出现的swap内存泄漏问题,该进程swap内存持续增长至4.5GB且未释放,导致相机应用ANR。通过日志分析发现,swap内存增长与相机运行状态无关,推测是长时间低内存压力触发内核压缩机制所致。进一步复现发现,该问题仅在高负载老化版本中概率性出现,根源在于FDNode模块的多线程同步缺陷:性能劣化时,线程竞争导致cv_face_destroy_tracker未执行论,性能极差下,非常低概率下,线程同步异常导致内存泄漏。!!下一篇讲解。

1881

Android App 内存泄露之Thread

Thread 内存泄露 线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。 1.看一下下面是否存在问题 public class ThreadActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedIns

The Tech-Dragon 8388

OpencvSharp学习笔记(一):图片的打开,保存灰度化,保存

近来萌生了学习OpenCv的想法,经过度娘得知老夫会的C#不能直接用OpenCv,只能用他的儿子OpenCvSharp与EmguCV,奈何奈何,这两玩意的资料少的出奇,只能慢慢的摸索了,EmguCV先不说,老夫找到了牛批的资料,先摸索OpencvSharp吧 首先打开VS通过Nuget安装 选择版本后点击安装就OK了. 安装完成后,引用里面就有以下的玩意儿了… 废话不多说了,在写程序前先 using OpenCvSharp 图片打开,灰度化,保存代码如下: static void Main(strin

猥琐de专注 7186

ThreadLocal内存泄漏原理解析

ThreadLocal内存泄漏原理解析

jack__love的博客 5245

思科路由器、交换机组网实验报告

通过思科模拟器搭建路由交换网络

ghj528的博客 1334

从零开始:使用英伟达nx开发板部署目标检测算法的全过程

英伟达nx开发板烧录、依赖安装、开发板联网

weixin_51192760的博客 3761

Windows 编程中,CloseHandle(hThread);为什么紧跟着CreatThread

hThread = CreateThread( NULL, 0, ThreadFunc, NULL, 0, &dwThreadId); CloseHandle(hThread); 如上面这样的代码,原因为:创建线程后返回了线程句柄,新创建的线程内核对象的使用计数是2,一个是线程本身,一个是创建线程的线程,创建线程的线程closehandle后,新的线程的内核对象使用计数为1,当这个新线

lg546982075的博客 715

记一次在JAVA中客户端使用axis调用webservice服务端出现的异常:Unmarshalling Error: For input string: ""

在使axis调用webservice服务端,参照网上给的demo: Call call = (Call) service.createCall(); call.setTargetEndpointAddress(endpoint);//设置服务请求路径 QName qn = new QName(name); call.setOperationName(qn); call.addParamet

kry1201的专栏 8080

CreateThread 创建线程所引起的内存泄漏的问题

内存泄漏编辑 在很多参考书上,都说不要用CreateThread 创建线程、并用CloseHandle来关闭这个线程,因为这样做会导致内存泄漏,而应该用_beginthread来创建线程,_endthread来销毁线程。其实,真正的原因并非如此。看如下一段代码: 1 2 3 4 5 6 7 8 HAND

hkwlg1314的博客 3912

2026年Java 开发工程师常见面试简答题

本文整理了Java开发工程师面试常见简答题及详细解析,涵盖Java基础、集合框架、并发编程、JVM等核心考点。主要内容包括:1. Java基础概念:JDK/JRE/JVM区别、面向对象特性、重载与重写、接口与抽象类、String特性等 2. 集合框架:ArrayList/LinkedList区别、HashMap实现原理、线程安全方案、集合类型对比 3. 并发编程:synchronized原理、volatile作用、线程创建方式、线程池参数与策略、死锁处理 4. JVM相关:内存区域划分、垃圾回收算法、类加载

不务正业的猿 369

1998年高教社杯全国大学生数学建模竞赛 B 题:《灾情巡视路线》真题解析与 MATLAB 解决方案

🏆 本文已收录于专栏:《滚雪球学数学建模(含历年真题)》,持续更新最新及历年数学建模竞赛资料,每篇内容力求做到“问题讲透、模型讲清、代码可用、论文可参考”,帮助你从零开始逐步建立完整的数学建模知识体系。

**My Coding Family** 883

内存泄漏和内存溢出的总结

现在的应用中内存的管理是一个大的问题,如何保证不因内存问题影响程序的使用和用户体验效果,这里是我看到的网络上的一篇不错的文章,对其进行了简单的整理。让我们来共同学习 内存的重要性:Android主要应用在嵌入式设备当中,而嵌入式设备由于一些众所周知的条件限制,通常都不会有很高的配置,特别是内存是比较有限的。如果我们编写的代码当中有太多的对内存使用不当的地方,难免会使得我们的设备运行缓慢,甚至

qq_2790289459的博客 543

7、Python高光谱分析工具(PyHAT)简介

Python高光谱分析工具(PyHAT)是一个开源、跨平台的Python库及图形用户界面,用于行星光谱数据的可视化与分析。它支持多种高光谱传感器数据,如火星勘测轨道飞行器的CRISM、月船1号的M3以及SELENE Kaguya SP点光谱仪,提供预处理、衍生产品生成、统计学习和机器学习分析功能。PyHAT基于Pandas和NumPy构建,兼容Jupyter和QGIS环境,旨在解决现有光谱分析方法缺乏开源实现、难以探索性分析和算法分散的问题。其模块化架构涵盖数据输入/输出、通用光谱变换、测绘与点观测工具及高

aa123的博客 138

TransmittableThreadLocal内存泄漏问题排查解决

线上使用TransmittableThreadLocal解决线程池等会池化复用线程的执行组件情况下,提供ThreadLocal值的传递功能,解决异步执行时上下文传递的问题。运行一段时间后,出现内存泄漏,进程被杀。后续回滚。进行分析。

liuhstop1的博客 1735

STM32 实现 4*4 矩阵键盘扫描(HAL库、标准库 都适用)

本文实现的代码是基于STM32HAL库的基础上的,不过标准库也可以用,只是调用的库函数不同,逻辑跟配置是一样的,按我这里的逻辑来配置即可。 1、键盘原理图: 原理举例:先把 F0-F7 内部拉高,这样这个8个引脚都是高电平,然后就进行列扫描。例如:假如按下3按钮,Y3 列扫描,把F4先拉低,然后读取F0-F3的状态,就会读出为1110,这就可 以知道是F3行拉低了,同时这时候是程序控制F4拉低的,这样就可以知道是F4列导致它转态变化了的,这样就可以定位出是F4列F3行的按键按下了;其他的列也是这样子扫描

lhh_qrsly的博客 7058

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

TransmittableThreadLocal内存泄漏问题排查

通过上图可以看到第一次执行异步任务的时候能够获取到值,之后主线程进行remove操作,主线程获取不到为空,第二个异步任务执行的时候能够获取到值。执行第二次异步任务的时候,获取值为空是因为异步任务用TtlRunnable修饰,用它修饰的话,执行任务前会将用父线程也就是主线程的上下文信息给子线程,这个时候主线程已经被清空,所以展示为空。执行异步任务的时候,会初始化线程,初始化线程的特性会子线程也继承父线程;可以看到最后一个异步任务也拿不到值了,说明异步线程的上下文也被清空了。这个线程绑定的值有值了。

yearraey的博客 581

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

linux内存一直在涨,linux下创建线程导致内存泄漏

用top发现virt的使用量一直在涨。于是可以断定有内存泄漏了,经过排查,最终确定原因出在多线程的问题上:代码如下:pthread_t thread_id;int ret=pthread_create(&thread_id, NULL, flush_thread_work, (void*)&m_sql_client);if(ret!=0){APPSCORE_ERROR("Threa...

weixin_29505609的博客 653

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

多线程中CString内存泄漏的解决方法。

‍多线程导致的内存泄漏DWORD WINAPI ConnectionWorkerProc(LPVOID pObject){CString strPath;CString strFileName;CString currentStr;TCHAR currentPath[512] = _T("");TCHAR sendPfilePath[256] = _T("");GetCurrentDirecto...

weixin_34297704的博客 734

利用MAT进行内存泄漏分析

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

大雀儿飞飞的专栏 4万+

线程分离 - 线程也会内存泄漏

线程分离 - 线程也会内存泄漏 线程退出后,释放了所有占用的资源嘛? 上述问题我们通过以下代码进行测试,不断地创建线程,每次创建线程计数器加一,只到创建线程失败,打印出已创建的线程数 ​ #include <stdio.h> #include <unistd.h> #include <pthread.h> ​ ​ void ...

MOSHIWANGJUE的博客 2512

分析 Java 的线程局部变量(ThreadLocal)内存泄漏

的核心作用是提供线程局部变量,即每个使用该变量的线程都拥有自己独立的变量副本,线程之间的变量互不干扰。其工作原理与线程的紧密相关。每个Thread对象都包含一个实例,这个以对象作为键,以线程局部变量的值作为值。当调用的get()或set()方法时,实际上是在当前线程的中进行查找或设置操作。以下是一个简单的示例代码,展示了});});t1.start();t2.start();在上述代码中,线程t1和t2分别设置了不同的变量值,它们之间互不影响。

潜意识Java的博客 1118

【Linux内存泄漏专题】如何分析Linux内存泄漏问题?

在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

Randy-LZY的博客 3000

内存泄漏、多线程Debug技巧总结

一些博主常用的Debug技巧

不定期更新系统使用、编程小技巧,哔哩哔哩账号:https://space.bilibili.com/399455629,欢迎关注 1287

【故障诊断】内存泄漏?线程死锁?一文掌握 jstack 与 jmap 分析技巧

jstack 是你的线程侦探,专治各种死锁、阻塞、CPU过高的“线程病”。关键看线程状态和锁的持有关系。jmap 是你的内存法医,通过解剖Heap Dump文件来诊断内存泄漏的根源。关键靠MAT等工具分析引用链。

✨ 欢迎来唠嗑、切磋、一起成长!👋 884

ThreadLocal线程自己的变量 和 内存泄漏

在setInitialValue方法中,类似于set方法的实现,都是判断当前线程的threadLocals变量是否为null,是则添加本地变量(这个时候由于是初始化,所以添加的值为null),否则创建threadLocals变量,同样添加的值为null。,它提供线程本地变量,如果创建一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个副本,在实际多线程操作的时候,操作的是自己本地内存中的变量,从而规避了线程安全问题。根据上面的例子,我们分析源码,数据是如何存取的。

黄彪博客 1037
上一篇: 内存泄漏分析一
下一篇: 内存泄漏分析三-Handler
wd_cloud
博客等级 码龄19年 733粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值