性能
Last updated
Was this helpful?
Last updated
Was this helpful?
Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收;另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收。
内存泄露的危害就是会使虚拟机占用内存过高,导致OOM(内存溢出),程序出错。 对于Android应用来说,就是你的用户打开一个Activity,使用完之后关闭它,内存泄露;又打开,又关闭,又泄露;几次之后,程序占用内存超过系统限制,FC。
|Android性能优化视频,文档以及工具
|胡凯—腾讯Android开发工程师
|经典
|Android Monitor
Android Monitor
LeakCanary
MAT【推荐】
Heap Viewer
Allocation Traker
集合类泄露
如果某个集合是全局性的变量(比如 static 修饰),集合内直接存放一些占用大量内存的对象(而不是通过弱引用存放),那么随着集合 size 的增大,会导致内存占用不断上升,而在 Activity 等销毁时,集合中的这些对象无法被回收,导致内存泄露。比如我们喜欢通过静态 HashMap 做一些缓存之类的事,这种情况要小心,集合内对象建议采用弱引用的方式存取,并考虑在不需要的时候手动释放。
单例造成的内存泄露
单例的静态特性导致其生命周期同应用一样长。
有时创建单例时如果我们需要Context对象,如果传入的是Application的Context那么不会有问题。如果传入的是Activity的Context对象,那么当Activity生命周期结束时,该Activity的引用依然被单例持有,所以不会被回收,而单例的生命周期又是跟应用一样长,所以这就造成了内存泄露。 解决办法一:在创建单例的构造中不直接用传进来的context,而是通过这个context获取Application的Context。代码如下:
第二种解决方案:在构造单例时不需要传入 context,直接在我们的 Application 中写一个静态方法,方法内通过 getApplicationContext 返回 context,然后在单例中直接调用这个静态方法获取 context。
非静态内部类造成的内存泄露
非静态内部类或匿名类因为持有外部类的引用,所以可以访问外部类的资源属性成员变量等;静态内部类不行。
因为普通内部类或匿名类依赖外部类,所以必须先创建外部类,再创建普通内部类或匿名类;而静态内部类随时都可以在其他外部类中创建。
资源未关闭造成的内存泄露
WebView 的泄漏 Android 中的 WebView 存在很大的兼容性问题,有些 WebView 甚至存在内存泄露的问题。所以通常根治这个问题的办法是为 WebView 开启另外一个进程,通过 AIDL 与主进程进行通信, WebView 所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。
在 Java 中,非静态内部类(包括匿名内部类,比如 Handler, Runnable匿名内部类最容易导致内存泄露)会持有外部类对象的强引用(如 Activity),而静态的内部类则不会引用外部类对象。