Java是一种垃圾回收语言。它的好处是开发者不需要专门管理内存分配,减少了部分故障(segmentationfault)导致的应用程序崩溃,防止未释放的内存栈(堆)可能过度拥挤,所以写的代码更安全。不幸的是,Java中仍然存在很多逻辑漏洞,很容易导致内存泄漏。如果您不小心,您的Android应用程序很容易浪费未释放的内存,最终导致内存不足(OOM)错误。传统内存泄漏的原因是:当对象的所有引用都已释放时,对象还没有被释放。(译者注:游标忘记关闭等)逻辑内存泄漏的原因是:当应用程序不再需要这个对象时,对该对象的所有引用还没有被释放。如果持有对象的强引用,垃圾收集器就无法回收内存中的对象。在Android开发中,最容易出现内存泄漏问题的就是Context。比如Activity的Context中包含了大量的内存引用,比如ViewHierarchies等资源。Context一旦泄露,也就意味着泄露了它指向的所有对象。Android机器内存有限,内存泄露过多很容易导致OOM。检测逻辑内存泄漏需要主观判断,尤其是在对象的生命周期不明确的情况下。好在Activity有明确的生命周期,很容易找到泄漏的原因。Activity.onDestroy()被视为Activity生命的结束。在编程上,应该销毁,或者Android系统需要回收内存(译者注:当内存不够时,Android会回收看不见的Activity)。如果执行到这个方法,栈中仍然存在对Activity的强引用,垃圾回收器将无法将其标记为回收内存,而我们的初衷是回收它!结果是Activity存在于其生命周期之外。Activity是重量级对象,应该由Android系统处理。然而,逻辑内存泄漏总是在不经意间发生。(译者注:我曾经试过一个导致20M内存泄漏的Activity)。在Android中,导致潜在内存泄漏的陷阱不外乎两种:全局进程(process-global)的静态变量。无论应用程序的状态如何,这个怪物都持有对Activity的强引用。活动生命周期之外的线程。不会清除对Activity的强引用。查看您是否遇到过以下情况。StaticActivities在类中定义了一个静态的Activity变量,并将当前运行的Activity实例赋值给这个静态变量。如果Activity生命周期结束后不清除这个静态变量,就会造成内存泄漏。因为静态变量贯穿于应用程序的生命周期,泄漏的Activity会一直存在于应用程序进程中,不会被垃圾回收器回收。staticActivityactivity;voidsetStaticActivity(){activity=this;}ViewsaButton=findViewById(R.id.sa_button);saButton.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){setStaticActivity();nextActivity();}});内存泄漏1——静态ActivityStaticViews在单例模式下也会出现类似的情况。如果Activity被频繁使用,在内存中保留一个实例是非常实用的。如前所述,强行延长Activity的生命周期是相当危险和不必要的,无论如何也不应该这样做。特例:如果一个View初始化消耗的资源比较多,并且在Activity的生命周期内保持不变,可以做成静态的加载到视图树(ViewHierachy)中。像这样,当Activity被销毁时,它应该释放资源。(译者注:示例代码并没有释放内存,只是将这个静态视图设置为null,但是还是不推荐使用这个静态视图的方式)staticview;voidsetStaticView(){view=findViewById(R.id.sv_button);}ViewsvButton=findViewById(R.id.sv_button);svButton.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){setStaticView();nextActivity();}});MemoryLeak2-StaticViewInner类继续,假设Activity中有一个内部类,可以提高可读性和封装性。就像我们创建一个内部类并持有一个静态变量的引用一样,恭喜,内存泄漏离你不远了(译者注:销毁时空白,嗯)。privatestaticObjectinner;voidcreateInnerClass(){classInnerClass{}inner=newInnerClass();}ViewicButton=findViewById(R.id.ic_button);icButton.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){createInnerClass();nextActivity();}});内存泄漏3-内部类内部类的优点之一是它可以访问外部类。不幸的是,内存泄漏的原因是内部类持有对外部类实例的强引用。匿名类类似地,匿名类也维护对外部类的引用。所以当你在Activity中定义匿名AsyncTsk时很容易发生内存泄漏。当异步任务在后台执行耗时任务时,Activity不幸被销毁(译者注:用户退出,系统回收),AsyncTask持有的Activity实例直到被垃圾回收器回收为止异步任务结束。voidstartAsyncTask(){newAsyncTask
