android,性能优化,内存优化管理,高级缓存

http://blog.csdn.net/liao3841054/article/details/7011757

这近做的项目老是出现内存溢出,项目一大,稍不注意就会出现这样 的问题。导致第二个版本框架重写,重要的还是继承体系过深,导致垃圾回收总是回收不了,最后导致内存沾满无法释放。

内存对于手机来说是非常重要的。

下面总结了我们在注意创建对象时的规则,以及怎么更好更快的实行GC回收,和怎么构建高速的对象cace缓冲。

1 避免循环遍历的创建对象,哪怕对象很小,也是要占资源的。

2 尽量使对象符合垃圾回收的标准

3 不要采用过深的继承体系

4 访问本地变量优于访问类中的变量

1.对象的强、软、弱和虚引用
   在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

⑴强引用(StrongReference)
    强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

⑵软引用(SoftReference)

    如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

⑶弱引用(WeakReference)

    弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

⑷虚引用(PhantomReference)

    “虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);

   程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

2.对象可及性的判断

在很多时候,一个对象并不是从根集直接引用的,而是一个对象被其他对象引用,甚至同时被几个对象所引用,从而构成一个以根集为顶的树形结构。

◆单条引用路径可及性判断:在这条路径中,最弱的一个引用决定对象的可及性。
◆多条引用路径可及性判断:几条路径中,最强的一条的引用决定对象的可及性。

3.使用软引用构建敏感数据的缓存

3.1 为什么需要使用软引用

    首先,我们看一个雇员信息查询系统的实例。我们将使用一个Java语言实现的雇员信息查询系统查询存储在磁盘文件或者数据库中的雇员人事档案信息。作为一个用户,我们完全有可能需要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息(同样,我们在浏览WEB页面的时候也经常会使用“后退”按钮)。这时我们通常会有两种程序实现方式:一种是把过去查看过的雇员信息保存在内存中,每一个存储了雇员档案信息的Java对象的生命周期贯穿整个应用程序始终;另一种是当用户开始查看其他雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的Java对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该雇员的档案信息的时候,重新构建该雇员的信息。很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。我们知道,访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度。

3.2 如何使用软引用

    SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。

看下面代码:

[html] view
plain
copy

  1. MyObject aRef = new  MyObject();  
  2. SoftReference aSoftRef=new SoftReference(aRef);  

此时,对于这个MyObject对象,有两个引用路径,一个是来自SoftReference对象的软引用,一个来自变量aReference的强引用,所以这个MyObject对象是强可及对象。

随即,我们可以结束aReference对这个MyObject实例的强引用:

aRef = null;

   此后,这个MyObject对象成为了软可及对象。如果垃圾收集线程进行内存垃圾收集,并不会因为有一个SoftReference对该对象的引用而始终保留该对象。Java虚拟机的垃圾收集线程对软可及对象和其他一般Java对象进行了区别对待:软可及对象的清理是由垃圾收集线程根据其特定算法按照内存需求决定的。也就是说,垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软可反对象会被虚拟机尽可能保留。在回收这些对象之前,我们可以通过:

[html] view
plain
copy

  1. MyObject anotherRef=(MyObject)aSoftRef.get();  

重新获得对该实例的强引用。而回收之后,调用get()方法就只能得到null了。

3.3 使用ReferenceQueue清除失去了软引用对象的SoftReference

    作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,如:

[html] view
plain
copy

  1. ReferenceQueue queue = new ReferenceQueue();  
  2. SoftReference ref=new SoftReference(aMyObject, queue);  

    那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。

在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉。常用的方式为:

SoftReference ref = null;

while ((ref = (EmployeeRef) q.poll()) != null) {
   // 清除ref
}

理解了ReferenceQueue的工作机制之后,我们就可以开始构造一个Java对象的高速缓存器了。

3.4通过软可及对象重获方法实现Java对象的高速缓存

    利用Java2平台垃圾收集机制的特性以及前述的垃圾对象重获方法,我们通过一个雇员信息查询系统的小例子来说明如何构建一种高速缓存器来避免重复构建同一个对象带来的性能损失。我们将一个雇员的档案信息定义为一个Employee类:

[html] view
plain
copy

  1. public class Employee {  
  2.   private String id;// 雇员的标识号码  
  3.   private String name;// 雇员姓名  
  4.   private String department;// 该雇员所在部门  
  5.   private String Phone;// 该雇员联系电话  
  6.   private int salary;// 该雇员薪资  
  7.   private String origin;// 该雇员信息的来源  
  8. // 构造方法  
  9. public Employee(String id) {   
  10.      this.id = id;  
  11.      getDataFromlnfoCenter();  
  12. }  
  13. // 到数据库中取得雇员信息  
  14. private void getDataFromlnfoCenter() {  
  15.   // 和数据库建立连接井查询该雇员的信息,将查询结果赋值  
  16.   // 给name,department,plone,salary等变量  
  17.   // 同时将origin赋值为"From DataBase"  
  18. }  
  19. ……  
  20.    这个Employee类的构造方法中我们可以预见,如果每次需要查询一个雇员的信息。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。下面是一个对Employee对象进行缓存的缓存器的定义:  
  21. import java.lang.ref.ReferenceQueue;  
  22. import java.lang.ref.SoftReference;  
  23. import java.util.Hashtable;  
  24. public class EmployeeCache {  
  25.    static private EmployeeCache cache;// 一个Cache实例  
  26.    private Hashtable< String,EmployeeRef> employeeRefs;// 用于Chche内容的存储  
  27.    private ReferenceQueue< Employee> q;// 垃圾Reference的队列  
  28.    // 继承SoftReference,使得每一个实例都具有可识别的标识。  
  29.      private class EmployeeRef extends SoftReference< Employee> {  
  30.       private String _key = "";  
  31.        public EmployeeRef(Employee em, ReferenceQueue< Employee> q) {  
  32.       super(em, q);  
  33.       _key = em.getID();  
  34.     }  
  35.    }  
  36.   // 构建一个缓存器实例  
  37.     private EmployeeCache() {  
  38.       employeeRefs = new Hashtable<String,EmployeeRef>();  
  39.        q = new ReferenceQueue<Employee>();  
  40.    }  
  41.     // 取得缓存器实例  
  42. public static EmployeeCache getInstance() {  
  43.     if (cache == null) {  
  44.        cache = new EmployeeCache();  
  45.    }  
  46.     return cache;  
  47. }  
  48.   // 以软引用的方式对一个Employee对象的实例进行引用并保存该引用  
  49.    private void cacheEmployee(Employee em) {  
  50.     cleanCache();// 清除垃圾引用  
  51.      EmployeeRef ref = new EmployeeRef(em, q);  
  52.      employeeRefs.put(em.getID(), ref);  
  53.    }  
  54.    // 依据所指定的ID号,重新获取相应Employee对象的实例  
  55.     public Employee getEmployee(String ID) {  
  56.        Employee em = null;  
  57.         // 缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。  
  58.        if (employeeRefs.containsKey(ID)) {  
  59.           EmployeeRef ref = (EmployeeRef) employeeRefs.get(ID);  
  60.           em = (Employee) ref.get();  
  61.        }  
  62. // 如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,  
  63. // 并保存对这个新建实例的软引用  
  64. if (em == null) {  
  65.    em = new Employee(ID);  
  66.     System.out.println("Retrieve From EmployeeInfoCenter. ID=" + ID);  
  67.     this.cacheEmployee(em);  
  68.    }  
  69.    return em;  
  70.    }  
  71. private void cleanCache() {  
  72.    EmployeeRef ref = null;  
  73.    while ((ref = (EmployeeRef) q.poll()) != null) {  
  74.     employeeRefs.remove(ref._key);  
  75.    }  
  76.    }  
  77. // 清除Cache内的全部内容  
  78. public void clearCache() {  
  79.    cleanCache();  
  80.     employeeRefs.clear();  
  81.     System.gc();  
  82.     System.runFinalization();  
  83.    }  
  84. }  
  85.    
  86. 注:原来ReferenceQueue起到一个监听器的效果,当发现SoftReference.get()方法返回的是null值时,就会将SoftReference注册到自己里面队列里,当我们调用ReferenceQueue的poll()方法时,返回并删除该SoftReference。  
时间: 2024-09-20 00:55:52

android,性能优化,内存优化管理,高级缓存的相关文章

浅谈Android应用的内存优化及Handler的内存泄漏问题_Android

一.Android内存基础 物理内存与进程内存物理内存即移动设备上的RAM,当启动一个Android程序时,会启动一个Dalvik VM进程,系统会给它分配固定的内存空间(16M,32M不定),这块内存空间会映射到RAM上某个区域.然后这个Android程序就会运行在这块空间上.Java里会将这块空间分成Stack栈内存和Heap堆内存.stack里存放对象的引用,heap里存放实际对象数据. 在程序运行中会创建对象,如果未合理管理内存,比如不及时回收无效空间就会造成内存泄露,严重的话可能导致使

浅谈Android应用的内存优化及Handler的内存泄漏问题

一.Android内存基础 物理内存与进程内存 物理内存即移动设备上的RAM,当启动一个Android程序时,会启动一个Dalvik VM进程,系统会给它分配固定的内存空间(16M,32M不定),这块内存空间会映射到RAM上某个区域.然后这个Android程序就会运行在这块空间上.Java里会将这块空间分成Stack栈内存和Heap堆内存.stack里存放对象的引用,heap里存放实际对象数据. 在程序运行中会创建对象,如果未合理管理内存,比如不及时回收无效空间就会造成内存泄露,严重的话可能导致

Android性能系列-内存篇

内存篇 1) Memory, GC, and Performance 众所周知,与C/C++需要通过手动编码来申请以及释放内存有所不同,Java拥有GC的机制.Android系统里面有一个Generational Heap Memory的模型,系统会根据内存中不同的内存数据类型分别执行不同的GC操作.例如,最近刚分配的对象会放在Young Generation区域,这个区域的对象通常都是会快速被创建并且很快被销毁回收的,同时这个区域的GC操作速度也是比Old Generation区域的GC操作速

ANDROID内存优化(大汇总——中)

写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上把网上搜集的各种内存零散知识点进行汇总.挑选.简化后整理而成. 所以我将本文定义为一个工具类的文章,如果你在ANDROID开发中遇到关于内存问题,或者马上要参加面试,或者就是单纯的学习或复习一下内存相关知识,都欢迎阅读.(本文最后我会尽量列出所参考的文章). OOM: 内存泄露可以引发很多的问题: 1.程序卡顿,响应速度慢(内存占用高时JVM虚拟机会频繁触发GC) 2.莫名消失(当你的程序所占内存越大,它在

android开发中的内存优化

一.Android应用程序内存优化 在开发Android App的过程中,经常会遇到内存方面的压力,比如OOM,或者频繁GC.本文不打算涵盖内存优化的所有方面,只是介绍一下我自己遇到的问题和解决方法. 1.确定频繁分配内存的代码路径 一般来说,频繁分配内存的路径可能会是绘制(draw)相关的方法,排版(layout)相关的方法,某些回调方法(特别是传感器回调方法).你可能会检查这部分代码,然后优化它.但是,内存分配可能发生在调用链的更下面,检查代码非常困难.这里推荐一个工具,DDMS下的Allo

Android群英传笔记——第十章:Android性能优化

Android群英传笔记--第十章:Android性能优化 随着Android应用增多,功能越来越复杂,布局也越来越丰富了,而这些也成为了阻碍一个应用流畅运行,因此,对复杂的功能进行性能优化是创造高质量应用的基础,本章节将为大家展示几种性能优化的方法,帮助开发者快速的构建运行速度快,相应速度快的应用程序 布局优化 内存优化 使用各种工具进行分析,优化 一.布局优化 系统在渲染图片的时候需要消耗大量的资源,一个好的UI,不仅要有良好的视觉体验,更应该具有良好的使用体验,因此布局优化就显得很重要了

windows系统内存优化九大绝招

如何优化内存的管理,提高内存的使用效率,尽可能地提高运行速度,是我们所关心的问题.下面介绍在Windows操作系统中,提高内存的使用效率和优化内存管理的几种方法. 1.改变页面文件的位置 其目的主要是为了保持虚拟内存的连续性.因为硬盘读取数据是靠磁头在磁性物质上读取,页面文件放在磁盘上的不同区域,磁头就要跳来跳去,自然不利于提高效率.而且系统盘文件众多,虚拟内存肯定不连续,因此要将其放到其他盘上.改变页面文件位置的方法是:用鼠标右键点击"我的电脑",选择"属性→高级→性能设置

试试SQLSERVER2014的内存优化表

原文:试试SQLSERVER2014的内存优化表 试试SQLSERVER2014的内存优化表 SQL Server 2014中的内存引擎(代号为Hekaton)将OLTP提升到了新的高度. 现在,存储引擎已整合进当前的数据库管理系统,而使用先进内存技术来支持大规模OLTP工作负载. 就算如此,要利用此新功能,数据库必须包含"内存优化"文件组和表 即所配置的文件组和表使用Hekaton技术. 幸运的是,SQL Server 2014使这一过程变得非常简单直接. 要说明其工作原理,我们来创

【宝贵经验】Android性能优化之内存优化实战

1. Memory Leak 内存泄漏:对于Java来说,就是new出来的Object 放在Heap上无法被GC回收(内存中存在无法被回收的对象):内存泄漏发生时的主要表现为内存抖动,可用内存慢慢变少. 1.1 Memory Monitor AndroidStudio自带的Memory Monitor可以方便的观察堆内存的分配情况,并且可以粗略的观察有没有Memory Leak. 频繁的内存抖动,可能存在内存泄漏 A:initiate GC 手动触发GC操作; B:Dump Java Heap

详解Android性能优化之内存泄漏_Android

综述 内存泄漏(memory leak)是指由于疏忽或错误造成程序未能释放已经不再使用的内存.那么在Android中,当一个对象持有Activity的引用,如果该对象不能被系统回收,那么当这个Activity不再使用时,这个Activity也不会被系统回收,那这么以来便出现了内存泄漏的情况.在应用中内出现一次两次的内存泄漏获取不会出现什么影响,但是在应用长时间使用以后,若是存在大量的Activity无法被GC回收的话,最终会导致OOM的出现.那么我们在这就来分析一下导致内存泄漏的常见因素并且如何