2019-01-16 Android内存回收机制以及适配

1.垃圾收集算法的核心思想

Java语言建立了垃圾收集机制,用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。该机制可以有效防范动态内存分配中因内存垃圾过多而引发的内存耗尽,以及不恰当的内存释放所造成的内存非法引用。

 垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象,反之,如果对象不再被引用,则 为垃圾对象,可以回收其占据的空间,用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能,因此需要开发人员做比较深入的了解。

触发主GC(Garbage Collector)的条件

 JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。更值得关注的是主GC的触发条件,因为它对系统影响很明显。总的来说,有两个条件会触发主GC:

  ①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。

  ②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以 便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报“out of memory”的错误,Java应用将停止。

3.减少GC开销的措施

根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:

  (1)不要显式调用System.gc()

  此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。

  (2)尽量减少临时对象的使用

  临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。

  (3)对象不用时最好显式置为Null

  一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。

  (4)尽量使用StringBuffer,而不用String来累加字符串(详见blog另一篇文章JAVA中String与StringBuffer)

  由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如 Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的String对象,但 这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer 是可变长的,它在原有基础上进行扩增,不会产生中间对象。

  (5)能用基本类型如Int,Long,就不用Integer,Long对象

  基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。

  (6)尽量少用静态对象变量

  静态变量属于全局变量,不会被GC回收,它们会一直占用内存。

  (7)分散对象创建或删除的时间

  集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片, 从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC 的机会。



gc()函数的作用只是提醒虚拟机:程序员希望进行一次垃圾回收。但是它不能保证垃圾回收一定会进行,而且具体什么时候进行是取决于具体的虚拟机的,不同的虚拟机有不同的对策。在Davilk中,给程序分配的内存是根据机型厂商的不同而不同(现在大部分为32MB),在VM内部会将内存分为:java使用的内存,Native使用的内存,他们之间不能共享,当某一方面不足

的时候必须向VM申请,而不能直接使用另外一个的内存。

出现内存泄漏的可能性:

出现情况:

1. 数据库的cursor没有关闭

2.构造adapter时,没有使用缓存contentview

衍生listview的优化问题-----减少创建view的对象,充分使用contentview,可以使用一静态类来优化处理getview的过程

3.Bitmap对象不使用时采用recycle()释放内存

4.activity中的对象的生命周期大于activity

调试方法: DDMS==> HEAPSZIE==>dataobject==>[Total Size]



Android 内存浅析【管理、机制、分析】

一、 Android的内存机制

Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似。程序员通过new为对象分配内存,所有对象在java 堆内分配空间;然而对象的释放是由垃圾回收器来完成的。C/C++中的内存机制是“谁污染,谁治理”,java的就比较人性化了,给我们请了一个专门的清 洁工(GC)

二、GC是什么? 为什么要有GC?

GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以 自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。


垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?

对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对 象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可 以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。


间而忘记了释放。如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器GC验证这些对象是否不再需要。如果存在对 象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要确定对象所占内存将被回收,我们就要务必确认该对象不再会被使用。典型的做法就是把对象 数据成员设为null或者从集合中移除该对象。但当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。

Java带垃圾回收的机制,为什么还会内存泄露呢?举例:

[java]view plaincopyprint?

Vector v = new Vector(10);  

        for (int i = 1; i < 100; i++) {  

            Object o = new Object();  

            v.add(o);  

            o = null;  

        }// 此时,所有的Object对象都没有被释放,因为变量v引用这些对象。  

Java 内存泄露的根本原因就是 保存了不可能再被访问的变量类型的引用

六、Android的内存溢出

Android的内存溢出是如何发生的?

Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。也就是说我们所能利用的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误。

为什么会出现内存不够用的情况呢?我想原因主要有两个:

由于我们程序的失误,长期保持某些资源(如Context)的引用,造成内存泄露,资源造成得不到释放。保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制。



在Android适配方案小结

、(二)中,我们了解了一些基本概念。

600dp的含义是:代表这个设备的最短的那一边。

获取设备的最短边的代码是:Configuration config = getResources().getConfiguration();

int smallestScreenWidth = config.smallestScreenWidthDp;

这个时候拿smallestScreenWidth 与600想比较就可以知道该设备能否读取里面的资源了。

) 


除此之外,为了方便适配,在编码时我们还应该注意什么呢,主要有以下几点:

(1)多使用权重(android:layout_weight)

尤其是在tab切换布局,listview title及Item布局等情况下;

(2)设置宽度和高度时,尽量使用match_parent和wrap_content,避免把控件宽高设死;

(3)父容器布局选用

多使用RelativeLayout,FrameLayout,GridLayout等,减少布局层次。当然,在使用

权重时,得采用LinearLayout;

(4) 在xml里,设置高度、宽度采用dp(dip),设置字体采用sp。

(应该注意,在代码里面,我们写的setHeight(...)单位是px)

那么在具体开发中,我们应该注意什么呢。

首先,我们必须要知道,其实适配的关键在于两点:

(1)不同分辨率设备的适配,这点在单位的使用上用dp、sp以及图片资源存放于不同的drawable文件夹就可以解决问题;

(2)不同尺寸的适配,这点主要靠将相关值以及布局文件放置于不同的文件夹中来解决。

2.1 values文件夹

可以在工程下创建不同的values文件夹:values-sw480dp, values-sw600dp,

values-sw720dp-land等。比如一个控件的宽度,在10寸pad上是10dp,在8寸pad

上是5dp。这时,你可以定义一个变量,button_width,然后在values-sw600dp

下写5dp,在values-sw720-land下写

10dp。这样就达到了在不同尺寸pad上,

相应控件大小不一样的效果。

2.1 layout文件夹

如果在不同尺寸设备上展示的布局有明显差别,仅仅用values不同已经难以控制,

那么就可以考虑写不同的布局文件置于不同的layout文件夹下,android会根据设备

尺寸去加载相应文件夹下的布局文件。如:layout-sw480dp,layout-sw600dp,

layout-sw700dp等。

值得注意的是,如果不是很有必要,尽量采用2.1方案,方便维护。如果尺寸和分辨率都不同,

那么就要结合(1)、(2)考虑了。

(补充:其实values文件夹和layout文件夹不仅仅是根据尺寸判断,也和分辨率有关,不过在通常情况下,

综合计算考虑,仅根据尺寸判断就可以了:

你可能感兴趣的:(2019-01-16 Android内存回收机制以及适配)