搜档网
当前位置:搜档网 › android内存管理-MAT与防范手段

android内存管理-MAT与防范手段

android内存管理-MAT与防范手段
android内存管理-MAT与防范手段

内存管理与防范手段

目录

内存管理与防范手段 (1)

一.内存分配跟踪工具DDMS–>Allocation tracker 使用 (2)

二.内存监测工具DDMS-->Heap (2)

三.内存分析工具MAT(MemoryAnalyzerTool) (3)

1.生成.hprof文件 (4)

2.使用MAT导入.hprof文件 (5)

3.使用MAT的视图工具分析内存 (5)

四.MAT使用实例 (5)

1.生成heap dump (7)

2.用MAT分析heap dumps (9)

3.使用MAT比较heap dumps (11)

五.防范不良代码 (11)

1.查询数据库没有关闭游标 (11)

2.缓存convertView (12)

3.Bitmap对象释放内存 (13)

4.释放对象的引用 (13)

5.Context的使用 (14)

6.线程 (17)

7.其他 (20)

六.优化代码 (20)

1.使用自身方法(Use Native Methods) (20)

2.使用虚拟优于使用接口 (20)

3.使用静态优于使用虚拟 (20)

4.尽可能避免使用内在的Get、Set方法 (20)

5.缓冲属性调用Cache Field Lookups (21)

6.声明Final常量 (21)

7.慎重使用增强型For循环语句 (22)

8.避免列举类型Avoid Enums (23)

9.通过内联类使用包空间 (23)

10.避免浮点类型的使用 (24)

11.一些标准操作的时间比较 (24)

12.为响应灵敏性设计 (25)

一.内存分配跟踪工具DDMS–>Allocation tracker 使用

运行DDMS,只需简单的选择应用进程并单击Allocation tracker标签,就会打开一个新的窗口,单击“Start Tracing”按钮;然后,让应用运行你想分析的代码。运行完毕后,单击“Get Allocations”按钮,一个已分配对象的列表就会出现第一个表格中。单击第一个表格中的任何一项,在表格二中就会出现导致该内存分配的栈跟踪信息。通过allocation tracker,不仅知道分配了哪类对象,还可以知道在哪个线程、哪个类、哪个文件的哪一行。

尽管在性能关键的代码路径上移除所有的内存分配操作不是必须的,甚至有时候是不可能的,但allocation tracker可以帮你识别代码中的一些重要问题。举例来说,许多应用中发现的一个普遍错误:每次进行绘制都创建一个新的Paint对象。将Paint的创建移到一个实例区域里,是一个能极大提高程序性能的简单举措。

二.内存监测工具DDMS-->Heap

无论怎么小心,想完全避免badcode是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方。Androidtools中的DDMS就带有一个很不错的内存监测工具Heap(这里我使eclipse的ADT插件,并以真机为例,在模拟器中的情况类似)。用Heap 监测应用进程使用内存情况的步骤如下:

1.启动eclipse后,切换到DDMS透视图,并确认Devices视图、Heap视图都是打开的;

2.将手机通过USB链接至电脑,链接时需要确认手机是处于“USB调试”模式,而不是作为“MassStorage”;

3.链接成功后,在DDMS的Devices视图中将会显示手机设备的序列号,以及设备中正在运行的部分进程信息;

4.点击选中想要监测的进程,比如system_process进程;

5.点击选中Devices视图界面中最上方一排图标中的“UpdateHeap”图标;

6.点击Heap视图中的“CauseGC”按钮;

7.此时在Heap视图中就会看到当前选中的进程的内存使用量的详细情况

a)点击“CauseGC”按钮相当于向虚拟机请求了一次gc操作;

b)当内存使用信息第一次显示以后,无须再不断的点击“CauseGC”,Heap视图界面会

定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化;

c)内存使用信息的各项参数根据名称即可知道其意思,在此不再赘述。

如何才能知道我们的程序是否有内存泄漏的可能性呢。这里需要注意一个值:Heap视图

中部有一个Type叫做dataobject,即数据对象,也就是我们的程序中大量存在的类类型的对象。在dataobject一行中有一列是“TotalSize”,其值就是当前进程中所有Java数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。可以这样判断:

a)不断的操作当前应用,同时注意观察dataobject的TotalSize值;

b)正常情况下TotalSize值都会稳定在一个有限的范围内,也就是说由于程序中的的代码

良好,没有造成对象不被垃圾回收的情况,所以说虽然我们不断的操作会不断的生成很多对象,而在虚拟机不断的进行GC的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;

c)反之如果代码中存在没有释放对象引用的情况,则dataobject的TotalSize值在每次GC

后不会有明显的回落,随着操作次数的增多TotalSize的值会越来越大,直到到达一个上限后导致进程被kill掉。

d)此处已system_process进程为例,在我的测试环境中system_process进程所占用的内存

的dataobject的TotalSize正常情况下会稳定在2.2~2.8之间,而当其值超过3.55后进程就会被kill。

三.内存分析工具MAT(MemoryAnalyzerTool)

如果使用DDMS确实发现了我们的程序中存在内存泄漏,那又如何定位到具体出现问题

的代码片段,最终找到问题所在呢?如果从头到尾的分析代码逻辑,那肯定会把人逼疯,特别是在维护别人写的代码的时候。这里介绍一个极好的内存分析工具MemoryAnalyzerTool(MAT)。

MAT是一个Eclipse插件,同时也有单独的RCP客户端。官方下载地址、MAT介绍和详细的使用教程请参见:https://www.sodocs.net/doc/0f14600925.html,/mat,在此不进行说明了。另外在MAT安装后的帮助

文档里也有完备的使用教程。在此仅举例说明其使用方法。我自己使用的是MAT的eclipse

插件,使用插件要比RCP稍微方便一些。

使用MAT进行内存分析需要几个步骤,包括:生成.hprof文件、打开MAT并导入.hprof 文件、使用MAT的视图工具分析内存。以下详细介绍。

1.生成.hprof文件

a)打开eclipse并切换到DDMS透视图,同时确认Devices、Heap和logcat视图已经打开了;

b)将手机设备链接到电脑,并确保使用“USB调试”模式链接,而不是“Mass Storage“模

式;

c)链接成功后在Devices视图中就会看到设备的序列号,和设备中正在运行的部分进程;

d)点击选中想要分析的应用的进程,在Devices视图上方的一行图标按钮中,同时选中

“Update Heap”和“Dump HPROF file”两个按钮;

e)这是DDMS工具将会自动生成当前选中进程的.hprof文件,并将其进行转换后存放在

sdcard当中,如果你已经安装了MAT插件,那么此时MAT将会自动被启用,并开始对.hprof 文件进行分析;

注意:第4步和第5步能够正常使用前提是我们需要有sdcard,并且当前进程有向sdcard中写入的权限(WRITE_EXTERNAL_STORAGE),否则.hprof文件不会被生成,在logcat中会显示诸如ERROR/dalvikvm(8574):hprof:can'topen/sdcard/com.xxx.hprof-hptemp:Permissiondenied.的信息。如果我们没有sdcard,或者当前进程没有向sdcard写入的权限(如system_process),那我们可以这样做:

在当前程序中,例如framework中某些代码中,可以使用android.os.Debug中的

public static void dumpHprofData(String fileName) throws IOException方法,手动的指定.hprof 文件的生成位置。例如:

xxxButton.setOnClickListener(newView.OnClickListener(){

publicvoidonClick(Viewview){

android.os.Debug.dumpHprofData("/data/temp/myapp.hprof");

......

}

}

上述代码意图是希望在xxxButton被点击的时候开始抓取内存使用信息,并保存在我们指定的位置:/data/temp/myapp.hprof,这样就没有权限的限制了,而且也无须用sdcard。但要保证/data/temp目录是存在的。这个路径可以自己定义,当然也可以写成sdcard当中的某个路径。

2.使用MAT导入.hprof文件

a)如果是eclipse自动生成的.hprof文件,可以使用MAT插件直接打开(可能是比较新的ADT

才支持);

b)如果eclipse自动生成的.hprof文件不能被MAT直接打开,或者是使用

android.os.Debug.dumpHprofData()方法手动生成的.hprof文件,则需要将.hprof文件进行转换,转换的方法:将.hprof文件拷贝到PC上的/ANDROID_SDK/tools目录下,并输入命令hprof-conv xxx.hprof yyy.hprof,其中xxx.hprof为原始文件,yyy.hprof为转换过后的文件。

转换过后的文件自动放在/ANDROID_SDK/tools目录下。OK,到此为止,.hprof文件处理完毕,可以用来分析内存泄露情况了。

c)在Eclipse中点击Windows->OpenPerspective->Other->MemoryAnalyzer,或者打

MemoryAnalyzerTool的RCP。在MAT中点击File->OpenFile,浏览并导入刚刚转换而得到的.hprof文件。

3.使用MAT的视图工具分析内存

导入.hprof文件以后,MAT会自动解析并生成报告,点击DominatorTree,并按Package

分组,选择自己所定义的Package类点右键,在弹出菜单中选择

Listobjects->Withincomingreferences。这时会列出所有可疑类,右键点击某一项,并选择PathtoGCRoots->excludeweak/softreferences,会进一步筛选出跟程序相关的所有有内存泄露的类。据此,可以追踪到代码中的某一个产生泄露的类。

具体的分析方法在MAT的官方网站和客户端的帮助文档中有十分详尽,使用MAT分析内存查找内存泄漏的根本思路,就是找到哪个类的对象的引用没有被释放,找到没有被释放的原因,也就可以很容易定位代码中的哪些片段的逻辑有问题了。

四.MAT使用实例

使用DDMS检查这个应用的heap使用情况。你可以使用下面的方法启动DDMS:

From Eclipse : click Window > Open Perspective>Other...>DDMS

在左边的面板选择进程com.founder.android.new.kyodo.activity,然后在工具条上边点击

heap updates按钮。

这个时候切换到DDMS的VMHeap分页。它会显示每次gc后heap内存的一些基本数据。要看第一次gc后的数据内容,点击CauseGC按钮:

1.生成heap dump

我们现在使用heap dump来追踪这个问题。点击DDMS工具条上面的Dump HPROF文件按钮,选择文件存储位置,然后在运行hprof-conv。

如果你使用ADT(它包含DDMS的插件)同时也在eclipse里面安装了MAT,点击“dump HPROF”按钮将会自动地做转换(用hprof-conv)同时会在eclipse里面打开转换后的hprof文件(它其实用MAT打开)。

将生成的.hprof文件导入到MAT中,选择Leak Suspects Report ,得到下图:

2.用MAT分析heap dumps

启动MAT然后加载刚才我们生成的HPROF文件。MAT是一个强大的工具,讲述它所有的特性超出了本文的范围,所以我只想演示一种你可以用来检测泄露的方法:直方图(Histogram)视图。它显示了一个可以排序的类实例的列表,内容包括:shallow heap(所有实例的内存使用总和),或者retained heap(所有类实例被分配的内存总和,里面也包括他们所有引用的对象)。

如果我们按照shallow heap排序,自从Android3.0(Honeycomb),Bitmap的像素数据被存储在byte数组里(之前是被存储在Dalvik的heap里),所以基于这个对象的大小来判断。

右击byte[]类然后选择List Objects>with incoming references。它会生成一个heap上的所有byte 数组的列表,在列表里,我们可以按照Shallow Heap的使用情况来排序。选择并展开一个比较大的对象,它将展示从根到这个对象的路径--就是一条保证对象有效的链条。

MAT不会明确告诉我们这就是泄露,因为它也不知道这个东西是不是程序还需要的,只有程序员知道。在这个案例里面,缓存使用的大量的内存会影响到后面的应用程序,所以我们可以考虑限制缓存的大小。

3.使用MAT比较heap dumps

调试内存泄露时,有时候适时比较2个地方的heap状态是很有用的。这时你就需要生成2个单独的HPROF文件(不要忘了转换格式)。下面是一些关于如何在MAT里比较2个heapdumps 的内容(有一点复杂):

a)第一个HPROF文件(using File>OpenHeapDump).

b)打开Histogram view.

c)在Navigation Historyview里(如果看不到就从Window>NavigationHistory找).右击

histogram然后选择AddtoCompareBasket.

d)打开第二个HPROF文件然后重做步骤2和3.

e)切换到CompareBasketview,然后点击ComparetheResults(视图右上角的红色"!"图标)。

五.防范不良代码

1.查询数据库没有关闭游标

程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。

示例代码:

Cursor cursor=getContentResolver().query(uri...);

if(cursor.moveToNext()){

......

}

修正示例代码:

Cursor cursor = null;

try{

cursor=getContentResolver().query(uri...);

if(cursor!=null && cursor.moveToNext()){

......

}

}finally{

if(cursor != null){

try{

cursor.close();

}catch(Exception e){

}

}

}

2.缓存convertView

以构造ListView的BaseAdapter为例,在BaseAdapter中提高了方法:

public View getView(int position,Viewconvert View, ViewGroup parent)

来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的listitem的view对象会被回收,然后被用来构造新出现的最下面的listitem。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的listitem的view对象(初始化时缓存中没有view对象则convertView是null)。

由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。ListView回收listitem 的view对象的过程可以查看:

android.widget.AbsListView.java-->void addScrapView(Viewscrap)方法。

示例代码:

public View getView(int position,Viewconvert View,ViewGroup parent){

View view = new Xxx(...);

......

return view;

}

修正示例代码:

public View getView(int position,Viewconvert View,ViewGroup parent){

View view = null;

if(convertView != null){

view = convertView;

populate(view , getItem(position));

...

}else{

view = new Xxx(...);

...

}

return view;

}

3.Bitmap对象释放内存

有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。

4.释放对象的引用

这种情况描述起来比较麻烦,举两个例子进行说明。

示例A:

假设有如下操作

public class DemoActivity extends Activity{

......

private Handler mHandler=...

private Object obj;

public void operation(){

obj = init Obj();

...

[Mark]

mHandler.post(new Runnable(){

public void run(){

use Obj(obj);

}

});

}

}

我们有一个成员变量obj,在operation()中我们希望能够将处理obj实例的操作post到某个线

程的MessageQueue中。在以上的代码中,即便是mHandler所在的线程使用完了obj所引用的对象,但这个对象仍然不会被垃圾回收掉,因为DemoActivity.obj还保有这个对象的引用。所以如果在DemoActivity中不再使用这个对象了,可以在[Mark]的位置释放对象的引用,而代码可以修改为:

......

public void operation(){

obj = init Obj();

...

final Object o= obj;

obj = null;

mHandler.post(new Runnable(){

public void run(){

useObj(o);

}

}

}

......

示例B:

假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。

但是如果在释放LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得system_process进程挂掉。

总之当一个生命周期较短的对象A,被一个生命周期较长的对象B保有其引用的情况下,在A 的生命周期结束时,要在B中清除掉对A的引用。

5.Context的使用

Android应用程序堆最大为16MB,至少在G1之前是这样,即便没有将这些内存用完的打算,开发者也应尽量减少内存开销以便其他应用能够在后台运行而不会被强制关闭。这样的话,

Android在内存中保存的应用越多,用户在应用间的切换就越快。Android应用程序的内存泄露问题,大部分时间里,这些问题都是源自同一个错误:对Context(上下文环境)的长时间引用。

在Android上,Context用于多种操作,但最多的还是用来加载和访问资源。这也是为什么所有的Widges在其构造函数中都有一个Context参数。常规的Android应用中,有两类Context:ActivityContext和ApplicationContext,通常前者被开发者传递给需要Context的类和方法。

1.@Override

2.Protected void onCreate(Bundle state){

3.super.onCreate(state);

4.

5.TextView label = new TextView(this);

https://www.sodocs.net/doc/0f14600925.html,bel.setText("Leaks are bad");

7.

8.setContentView(label);

9.}

这就意味着那些视图引用了整个Activity及其所拥有的一切:一般是整个视图层和所有资源。因此,如果泄露了这类Context(这里的泄露指的是引用Context,从而阻止了GC(垃圾回收)操作),就泄露了很多内存空间。如果不小心,泄露整个Activity是非常容易的事。

在进行屏幕方向改变的时候,系统默认做法是保持状态不变的情况下,销毁当前Activity 并重新创建一个新的Activity。这样做,Android会从资源文件中重新装载当前应用的UI。现在假设你写了一个带有很大一幅位图的应用,但你不想在每次屏幕旋转时都装载一次位图,最简单的做法就是将其保存在一个静态区域中:

1.Private static Drawables Background;

2.

3.@Override

4.Protected void onCreate(Bundle state){

5.super.onCreate(state);

6.

7.TextView label = new TextView(this);

https://www.sodocs.net/doc/0f14600925.html,bel.setText("Leaks are bad");

9.

10.if(sBackground == null){

11.sBackground=getDrawable(https://www.sodocs.net/doc/0f14600925.html,rge_bitmap);

12.}

https://www.sodocs.net/doc/0f14600925.html,bel.setBackgroundDrawable(sBackground);

14.

15.setContentView(label);

16.}

这段代码执行的快,同时也很有问题:在进行第一次屏幕方向改变的时候泄露了第一个Activity所占的内存空间。当一个Drawable连接到一个视图上时,视图被设置为Drawable上的一个回调,在上面的代码片段中,这就意味着Drawable引用了TextView,而TextView又引用了ActivityContext,ActivityContext又进一步引用了更多的东西(依赖与你的代码)。

上面这段示例是最简单的泄露ActivityContext的情况,你可以到HomeScreen'sSourceCode (查看unbindDrawables()方法)中看看我们是如何通过在Acitivity销毁时将存储Drawable的回调置为null来解决该问题的。如果再有兴趣的话,某些情况下会产生一个由泄露的Context 形成的链,这很糟糕,会很快使得内存耗尽。

有两种方法可以避免ActivityContext相关的内存泄露:最明显的一种是避免在ActivityContext自身的范围之外对其进行引用。上面这段示例展示了静态引用的情况,但对内部类和外部类的隐式引用同样都是危险的。第二种解决方法是用ApplicationContext,因为该Context与应用的生命周期一样长,并不依赖Activity的生命周期。如果想拥有一个生命期足够长的object(对象),但却需要给其一个必须的Context的话,别忘了ApplicationObject。获取ApplicationContext的方法很简单:执行Context.getApplicationContext()或

Activity.getApplication()。

总之,为了避免ActivityContext相关的内存泄露,记住下面几条:

a)不要长时间引用一个ActivityContext(引用周期应与Acitivity的生命周期一样长)

b)尝试使用ApplicationContext代替AcitivityContext

c)在Activity中,避免使用你无法控制其生命周期的非静态的内部类,使用静态的内部类,

并对Activity内部进行弱引用。就是在静态的内部类中对外部类进行弱引用,就如在ViewRoot及其W内部类中的做法那样

d)垃圾回收(GC)无法保证内存泄露

e)使用WeakReference代替强引用。比如可以使用WeakReference mContextRef; 该部分的详细内容也可以参考Android文档中Article部分。

6.线程

线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。

Public class MyActivity extends Activity{

Public void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(https://www.sodocs.net/doc/0f14600925.html,yout.main);

newMyThread().start();

}

Private class MyThread extends Thread{

@Override

Public void run(){

super.run();

//dosomthing

}

}

}

这段代码很平常也很简单,是我们经常使用的形式。我们思考一个问题:假设MyThread的run 函数是一个很费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,一般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。

由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity 也不会被销毁,因此就出现了内存泄露的问题。

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

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

第一、将线程的内部类,改为静态内部类。

第二、在线程内部采用弱引用保存Context引用。

解决的模型如下:

Public abstract class WeakAsyncTask extends

AsyncTask{

Protected WeakReference mTarget;

Public WeakAsyncTask(WeakTarget target){

mTarget = new WeakReference(target);

}

@Override

Protected final void onPreExecute(){

Final WeakTarget target=mTarget.get();

if(target != null){

this.onPreExecute(target);

}

}

@Override

Protected final Result doInBackground(Params...params){

Final WeakTarget target=mTarget.get();

if(target!=null){

return this.doInBackground(target,params);

}else{

Return null;

}

}

@Override

Protected final void onPostExecute(Result result){

Final WeakTarget target=mTarget.get();

if(target != null){

this.onPostExecute(target,result);

}

}

Protected void onPreExecute(WeakTarget target){

//Nodefaultaction

}

Protected abstract Result doInBackground(WeakTarget target,Params...params);

Protected void onPostExecute(WeakTarget target ,Result result){

//Nodefaultaction

}

}

7.其他

Android应用程序中最典型的需要注意释放资源的情况是在Activity的生命周期中,在onPause()、onStop()、onDestroy()方法中需要适当的释放资源的情况。

六.优化代码

1.使用自身方法(Use Native Methods)

当处理字符串的时候,不要犹豫,尽可能多的使用诸如String.indexOf()、https://www.sodocs.net/doc/0f14600925.html,stIndexOf()这样对象自身带有的方法。因为这些方法使用C/C++来实现的,要比在一个java循环中做同样的事情快10-100倍。还有一点要补充说明的是,这些自身方法使用的代价要比那些解释过的方法高很多,因而,对于细微的运算,尽量不用这类方法。

2.使用虚拟优于使用接口

假设你有一个HashMap对象,你可以声明它是一个HashMap或则只是一个Map:

Java代码

Map myMap1 = new HashMap();

HashMap myMap2 = new HashMap();

哪一个更好呢?

一般来说明智的做法是使用Map,因为它能够允许你改变Map接口执行上面的任何东西,但是这种“明智”的方法只是适用于常规的编程,对于嵌入式系统并不适合。通过接口引用来调用会花费2倍以上的时间,相对于通过具体的引用进行虚拟函数的调用。

如果你选择使用一个HashMap,因为它更适合于你的编程,那么使用Map会毫无价值。假定你有一个能重构你代码的集成编码环境,那么调用Map没有什么用处,即使你不确定你的程序从哪开头。(同样,public的API是一个例外,一个好的API的价值往往大于执行效率上的那点损失)

3.使用静态优于使用虚拟

如果你没有必要去访问对象的外部,那么使你的方法成为静态方法。它会被更快的调用,因为它不需要一个虚拟函数导向表。这同时也是一个很好的实践,因为它告诉你如何区分方法的性质(signature),调用这个方法不会改变对象的状态。

4.尽可能避免使用内在的Get、Set方法

C++编程语言,通常会使用Get方法(例如i = getCount())去取代直接访问这个属性(i=mCount)。这在C++编程里面是一个很好的习惯,因为编译器会把访问方式设置为Inline,并且如果想约束或调试属性访问,你只需要在任何时候添加一些代码。

在Android编程中,这不是一个很不好的主意。虚方法的调用会产生很多代价,比实例属性查询的代价还要多。我们应该在外部调用时使用Get和Set函数,但是在内部调用时,我们应该

浅谈Android(安卓)

浅谈Android--嵌入式操作系统 Android(读音:[??ndr?id],中文俗称安卓)是一个以Linux为基础的半开源操作系统,主要用于移动设备,由Google成立的Open Handset Alliance (OHA,开放手持设备联盟)持续领导与开发中。 --题记.维基百科说起嵌入式系统,曾经在保罗大叔的著作《黑客与画家》里看到多次,然后不明所以,就去查了嵌入式系统。如果说嵌入式系统给我的第一印象是硬件,那么是我还不知道嵌入式在我生活里已经出现了很多年了。 大到冰箱,自动存款机(ATM),小到电子手表,遥控器。在维基百科解答后,我对嵌入式直观的理解,是一种特定的植入硬件并极具针对性的计算机系统。 后来慢慢了解嵌入式的软件方面,就知道了嵌入式操作系统,而其中的佼佼者,就是如今已经超越ios,占据半壁江山的Android。 之所以会说Android,原因有二:一,因为Android如今炙手可热,在新一季度的日本手机软件营销额上,以Java等语言为Android系统开发的Apps,疯狂揽金,李开复断言在两年内,中国内地手机游戏软件市场,将会百花齐放;二,我虽并非研究Java也非致力于Android系统,但是Android系统的内核,却是我所熟悉的Linux内核。而我将自己的开发平台转移到Linux系统,并以Python,Perl以及Lisp语言作为未来的生存工具,所以,就让我们谈一谈Android。 题记中套用维基百科对于Android的介绍,主要的目的,就是为了澄清一件事实“认知”——Android并没有真正的中文名。 Google并没有为Android命名,只有为其版本取名,且翻译成中文:4.2.x Jelly Bean 果冻豆,4.0.x Ice Cream Sandwich 冰激凌三明治,3.x.x Honey

ANDROID BITMAP内存限制OOM,OUT OF MEMORY

ANDROID BITMAP内存限制OOM OUT OF MEMORY 在编写Android程序的时候,我们总是难免会碰到OOM的错误,那么这个错误究竟是怎么来的呢?我们先来看一下这段异常信息: 08-14 05:15:04.764: ERROR/dalvikvm-heap(264): 3528000-byte external allocation too large for this process. 08-14 05:15:04.764: ERROR/(264): VM won't let us allocate 3528000 bytes 08-14 05:15:04.764: DEBUG/skia(264): --- decoder->decode returned false 08-14 05:15:04.774: DEBUG/AndroidRuntime(264): Shutting down VM 08-14 05:15:04.774: WARN/dalvikvm(264): threadid=3: thread exiting with uncaught exception (group=0x4001b188) 08-14 05:15:04.774: ERROR/AndroidRuntime(264): Uncaught handler: thread main exiting due to uncaught exception 08-14 05:15:04.794: ERROR/AndroidRuntime(264): https://www.sodocs.net/doc/0f14600925.html,ng.OutOfMemoryError: bitmap size exceeds VM budget 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:447) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:346) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:372) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at com.xixun.test.HelloListView.onCreate(HelloListView.java:33) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.app.ActivityThread.access$2200(ActivityThread.java:119) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.os.Handler.dispatchMessage(Handler.java:99) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.os.Looper.loop(Looper.java:123) 08-14 05:15:04.794: ERROR/AndroidRuntime(264): at android.app.ActivityThread.main(ActivityThread.java:4363)

Android开发内存泄漏及检查工具使用培训资料

Android 开发内存泄漏及检查工具使用培 训资料

目录 1内存泄露 (3) 1.1 内存泄露的概念 (3) 1.2 开发人员注意事项 (4) 1.3 Android(java)中常见的引起内存泄露的代码示例 (4) 1.3.1查询数据库没有关闭游标 (6) 1.3.2 构造Adapter时,没有使用缓存的convertView (6) 1.3.3 Bitmap对象不在使用时调用recycle()释放内存 (7) 1.3.4 释放对象的引用 (8) 1.3.5 其他 (9) 2内存泄露的分析工具 (9) 2.1 内存监测工具DDMS --> Heap (9) 2.2 内存分析工具MAT (Memory Analyzer Tool) (10) 2.2.1 生成.hprof文件 (10) 2.2.2 使用MA T导入.hprof文件 (11) 2.2.3 使用MA T的视图工具分析内存 (12)

1内存泄露 Android 应用程序开发以Java语言为主,而Java编程中一个非常重要但却经常被忽视的问题就是内存使用的问题。Java的垃圾回收机制(Garbage Collection 以下简称GC)使得很多开发者并不关心内存使用的生命周期,只顾着申请内存,却不手动释放废弃的内存,而造成内存泄露,引起很多问题,甚至程序崩溃。Android的虚拟机Dalvik VM和java虚拟机JVM没有什么太大的区别,只是在字节码上稍做优化,所以Android应用开发中同样会出现内存泄露的问题。而且由于Android智能平台主要用于嵌入式产品开发,可用的内存资源更加稀少,所以对于我们Android应用开发人员来说,就更该了解Android程序的内存管理机制,避免内存泄露的发生。 1.1 内存泄露的概念 在计算机科学中,内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。内存泄漏与许多其他问题有着相似的症状,并且通常情况下只能由那些可以获得程序源代码的程序员才可以分析出来。然而,有不少人习惯于把任何不需要的内存使用的增加描述为内存泄漏,严格意义上来说这是不准确的。 一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。应用程序一般使用malloc,calloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。 这里我们只简单的理解,在java程序中,如果已经不再使用一个对象,但是仍然有引用指向它,GC就无法收回它,当然该对象占用的内存就无法再被使用,这就造成内存泄露。可能一个实例对象的内存泄露很小,并不会引起很大的问题。但是如果程序反复做此操作或者长期运行,造成内存不断泄露,终究会使程序无内存可用,只好被系统kill掉。在以下情况,内存泄漏导致较严重的后果: * 程序运行后置之不理,并且随着时间的流失消耗越来越多的内存(比如服务器上的后台任务,尤其是嵌入式系统中的后台任务,这些任务可能被运行后很多年内都置之不理); * 新的内存被频繁地分配,比如当显示电脑游戏或动画视频画面时; * 程序能够请求未被释放的内存(比如共享内存),甚至是在程序终止的时候; * 泄漏在操作系统内部发生; * 泄漏在系统关键驱动中发生; * 内存非常有限,比如在嵌入式系统或便携设备中; * 当运行于一个终止时内存并不自动释放的操作系统(比如AmigaOS)之上,而且一旦丢失只能通过重启来恢复。

Android的原理:关于应用自启动,占内存那些问题

Android的原理-不需要太多的剩余内存 Android用RAM的方式,跟windows、WM、Sybiam是两回事。在Android里,RAM被用满了是件好事。它意味着你可以快速打开之前打开的软件,回到之前的位置。所以Android 很有效的使用RAM,很多用户看到他们的RAM满了,就认为拖慢了他们的手机。而实际上,退出后重启这些程序才真正拖慢了手机的响应。而且这些自动杀进程的软件本身是个时刻活跃的进程,它始终在后台保持活跃使得CPU难以消停,反而增加了耗电量。 不用在意剩余内存的大小.其实很多人都是把使用其他系统的习惯带过来来了.安卓Android大多应用没有退出的设计其实是有道理的,这和系统对进程的调度机制有关系.如果你知道java,就能更清楚这机制了.其实和java的垃圾回收机制类似,系统有一个规则来回收内存.进行内存调度有个阀值,只有低于这个值系统才会按一个列表来关闭用户不需要的东西.当然这个值默认设置得很小,所以你会看到内存老在很少的数值徘徊.但事实上他并不影响速度.相反加快了下次启动应用的速度.这本来就是安卓Android标榜的优势之一,如果人为去关闭进程,没有太大必要.特别是自动关进程的软件. 到这里有人会说了,那为什么内存少的时候运行大型程序会慢呢?其实很简单,在内存剩余不多时打开大型程序,会触发系统自身的调进程调度策略,这是十分消耗系统资源的操作,特别是在一个程序频繁向系统申请内存的时候.这种情况下系统并不会关闭所有打开的进程,而是选择性关闭,频繁的调度自然会拖慢系统.所以,论坛上有个更改内存阀值的程序可以有一定改善. 但改动也可能带来一些问题,取决于值的设定. 那么,进程管理软件有无必要呢?有的.就是在运行大型程序之前,你可以手动关闭一些进程释放内存,可以显著的提高运行速度.但一些小程序,完全可交由系统自己管理.谈到这里,可能有的朋友会问,如果不关程序是不是会更耗电.我就说说安卓Android后台的原理,你就明白了.安卓Android 的应用在被切换到后台时,它其实已经被暂停了,并不会消耗cpu资源,只保留了运行状态.所以为什么有的程序切出去重进会到主界面.但是,一个程序如果想要在后台处理些东西,如音乐播放,它就会开启一个服务.服务可在后台持续运行,所以在后台耗电的也只有带服务的应用了.这个在进程管理软件里能看到,标签是service.所以没有带服务的应用在后台是完全不耗电的,没有必要关闭.这种设计本来就是一个非常好的设计,下次启动程序时,会更快,因为不需要读取界面资源,何必要关掉他们抹杀这个安卓Android的优点呢? 还有一个.为什么安卓Android一个应用看起来那么耗内存.大家知道,安卓Android上的应用是java,当然需要虚拟机,而安卓Android上的应用是带有独立虚拟机的,也就是每开一个应用就会打开一个独立的虚拟机.这样设计的原因是可以避免虚拟机崩溃导致整个系统崩溃,但代价就是需要更多内存. 以上这些设计确保了安卓Android的稳定性,正常情况下最多单个程序崩溃,但整个系统不会崩溃,也永远没有内存不足的提示出现.大家可能是被windows毒害得太深了,总想保留更多的内存,但实际上这并不一定会提升速度,相反却丧失了程序启动快的这一系统特色,很没必要.

Android 应用程序内存泄漏的分析

Android 应用程序内存泄漏的分析以前在学校里学习Java的时候,总是看到说,java是由垃圾收集器(GC)来管理内存回收的,所以当时形成的观念是Java不会产生内存泄漏,我们可以只管去申请内存,不需要关注内存回收,GC会帮我们完成。呵呵,很幼稚的想法,GC没那么聪明啊,理论及事实证明,我们的Java程序也是会有内存泄漏的。 (一)Java内存泄漏从何而来 一般来说内存泄漏有两种情况。一种情况如在C/C++语言中的,在堆中的分配的内存,没有将其释放,或者是在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。第一种情况,在Java中已经由于垃圾回收机制的引入,得到了很好的解决。所以,Java中的内存泄漏,主要指的是第二种情况。 (二)需要的工具 1.DDMS—Update heap Gause GC Heap 是DDMS自带的一个很不错的内存监控工具,下图红色框中最左边的图标就是该 工具的启动按钮,它能在Heap视图中显示选中进程的当前内存使用的详细情况。下图 框中最右边的是GC工具,很多时候我们使用Heap监控内存的时候要借助GC工具,点 击一次GC按钮就相当于向VM请求了一次GC操作。中间的按钮是Dump HPROF file,它 的功能相当于给内存拍一张照,然后将这些内存信息保存到hprof文件里面,在使用我 们的第二个工具MAT的时候会使用到这个功能。 2.MAT(Memory Analyzer Tool) Heap工具能给我们一个感性的认识,告诉我们程序当前的内存使用情况和是否存在内存 泄漏的肯能性。但是,如果我们想更详细,更深入的了解内存消耗的情况,找到问题所 在,那么我们还需要一个工具,就是MAT。这个工具是需要我们自己去下载的,可以下 载独立的MAT RCP 客户端,也可以以插件的形式安装到Eclipse里面,方便起见,推荐 后者。 安装方法: A.登录官网https://www.sodocs.net/doc/0f14600925.html,/mat/downloads.php B.下载MAT Eclipse插件安装包(红框所示,当然你也可是选择Update Site在线安装,个人觉得比较慢)

android内存管理-MAT与防范手段

内存管理与防范手段 目录 内存管理与防范手段 (1) 一.内存分配跟踪工具DDMS–>Allocation tracker 使用 (2) 二.内存监测工具DDMS-->Heap (2) 三.内存分析工具MAT(MemoryAnalyzerTool) (3) 1.生成.hprof文件 (4) 2.使用MAT导入.hprof文件 (5) 3.使用MAT的视图工具分析内存 (5) 四.MAT使用实例 (5) 1.生成heap dump (7) 2.用MAT分析heap dumps (9) 3.使用MAT比较heap dumps (11) 五.防范不良代码 (11) 1.查询数据库没有关闭游标 (11) 2.缓存convertView (12) 3.Bitmap对象释放内存 (13) 4.释放对象的引用 (13) 5.Context的使用 (14) 6.线程 (17) 7.其他 (20) 六.优化代码 (20) 1.使用自身方法(Use Native Methods) (20) 2.使用虚拟优于使用接口 (20) 3.使用静态优于使用虚拟 (20) 4.尽可能避免使用内在的Get、Set方法 (20) 5.缓冲属性调用Cache Field Lookups (21) 6.声明Final常量 (21) 7.慎重使用增强型For循环语句 (22) 8.避免列举类型Avoid Enums (23) 9.通过内联类使用包空间 (23) 10.避免浮点类型的使用 (24) 11.一些标准操作的时间比较 (24) 12.为响应灵敏性设计 (25)

一.内存分配跟踪工具DDMS–>Allocation tracker 使用 运行DDMS,只需简单的选择应用进程并单击Allocation tracker标签,就会打开一个新的窗口,单击“Start Tracing”按钮;然后,让应用运行你想分析的代码。运行完毕后,单击“Get Allocations”按钮,一个已分配对象的列表就会出现第一个表格中。单击第一个表格中的任何一项,在表格二中就会出现导致该内存分配的栈跟踪信息。通过allocation tracker,不仅知道分配了哪类对象,还可以知道在哪个线程、哪个类、哪个文件的哪一行。 尽管在性能关键的代码路径上移除所有的内存分配操作不是必须的,甚至有时候是不可能的,但allocation tracker可以帮你识别代码中的一些重要问题。举例来说,许多应用中发现的一个普遍错误:每次进行绘制都创建一个新的Paint对象。将Paint的创建移到一个实例区域里,是一个能极大提高程序性能的简单举措。 二.内存监测工具DDMS-->Heap 无论怎么小心,想完全避免badcode是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方。Androidtools中的DDMS就带有一个很不错的内存监测工具Heap(这里我使eclipse的ADT插件,并以真机为例,在模拟器中的情况类似)。用Heap 监测应用进程使用内存情况的步骤如下: 1.启动eclipse后,切换到DDMS透视图,并确认Devices视图、Heap视图都是打开的; 2.将手机通过USB链接至电脑,链接时需要确认手机是处于“USB调试”模式,而不是作为“MassStorage”; 3.链接成功后,在DDMS的Devices视图中将会显示手机设备的序列号,以及设备中正在运行的部分进程信息; 4.点击选中想要监测的进程,比如system_process进程; 5.点击选中Devices视图界面中最上方一排图标中的“UpdateHeap”图标; 6.点击Heap视图中的“CauseGC”按钮; 7.此时在Heap视图中就会看到当前选中的进程的内存使用量的详细情况 a)点击“CauseGC”按钮相当于向虚拟机请求了一次gc操作;

Android App内存泄露测试方法总结

Android App内存泄露测试方法总结 1、内存泄露 Android系统为每一个运行的程序都指定了一个最大运行内存,超过这个值则会触发OOM机制,反应在界面就是闪退、Crash现象,导致OOM发生的原因比如内存泄露或者是代码不考虑后果使用大量的资源,都有可能导致OOM出现的。OOM的临界值可以通过adb shell getprop | findstr “heap”查看到: 2、Android的GC机制 Android GC机制沿用了java的GC机制,当需要新内存去分配对象的时候而剩余不够的时候,会触发GC,把无用的对象回收掉,其中一个重要的算法便是分代式算法,这个算法把虚拟机分为年轻代、老年代和持久代,对象先分配到年轻代,然后GC多次后还存活的将会移动到老年代,老年代就不会频繁触发GC机制,一般触发频繁的都是年轻代的对象。 3、为什么会内存泄露 上面我们知道了GC机制,那么如果GC过后程序还是没有内存,那么会发生OOM,导致GC后还是没有足够内存分配新对象的主要原因就是内存泄露了。首先要知道内存泄露也就是GC不掉的根源是生命周期长的对象持有生命周期短的对象,导致无用的对象一直无法回收。以下是几个典型的分类: 1)**静态类相关的泄露:**static对象的生命周期伴随着整个程序的生命周期,所以这块要注意不要把一些对象引用添加到static对象里面去,会造成与之关联的对象无法回收。

2)各种资源的释放:包括cursor的关闭,IO流的关闭,bitmap的回收等,进行一些带有缓存的资源一定要关闭或者释放。 3)Handler的泄露:调用handler的delay的时候,会被认为对象是有用的,导致无法回收,还有handler开启线程去下载东西没有下载完成的时候,也会因为线程导致无法回收activity;或者使用handlerThread的时候,有延迟的方法,都会导致无法回收。其主要原因在于handler是持有activity的引用,主线程不是自带一个Looper然后给handler用,导致有关联关系。 4)各种注册引用方法:比如一个常驻的后台线程处理某些时间,把当前对象注册,因为一直持有对象引用,导致这个activity一直保留,所以不用的时候需要反注册。 5)把对象缓存进容器内却忘记remove掉:有时候为了加快页面响应,结果缓存一些对象到容器内,结果越加越多,然后挂掉。 4、系统级别的内存管理 1)LMK机制和oom_adj的值 Android内核有个专用的驱动low-memory-kill,当系统级别的内存不够的时候会根据oom_adj的值以及内存分配状况去kill掉某个进程,oom_adj可以在 /proc/[pid]/oom_adj看到,并且这个值会随着进程的状态改变而改变,比如系统进程一般是-16,越大越容易被干掉。 2)5个进程的优先级 前台进程:当前运行的,基本不死; 可见进程:界面可以见到,比如被遮挡; 服务进程:进程带后台服务的,比如播放器; 后台进程:点击home键,但不退出,就是后台进程了,有比较大几率会被杀;

如何清理释放Android手机内存空间

如何清理释放Android手机内存空间 和PC用户一样智能手机用户也会遇到手机存储不足的问题,对于Android手机来说因为系统不支持安装程序到SD卡,手机配置的存储容量也有限,很多用户都碰到过安装程序太多系统内存不足的问题。虽然Android 2.2系统开始已经支持Apps2SD功能,但是很多用户使用后发现Android 2.2系统下仍然有很多应用程序无法安装到SD卡,即可程序支持移动到SD 卡,但是还会保留一部分系统文件和隐私文件在手机内存里。另外还有一些程序像Widgets,动态壁纸和一些系统程序,如果安装在SD卡根本无法正常工作,内存不足依然是让很多用户感到棘手的问题。 不过Android作为一种优秀的移动操作系统,提供了几种可以清理和释放内存空间的办法,我们总结了下面几点希望可以帮助用户解决燃眉之急。 清理大型应用程序的缓存数据 ●通过清理程序的缓存文件,释放的内存空间会让你喜出望外 ●进入手机设置选项,选择设置>应用程序>管理应用程序 ●按一下Menu键,选择“按大小排序”选项(如果是Android 2.2手机先要选择已下载标 签),然后就可以按照应用程序大小排列所有手机安装的应用程序 ●点击一款列表中的应用程序,如果程序有缓存文件可以显示大小,直接点击“清除缓存” 选项就可以释放这些缓存文件占据的空间 ●有一些应用程序的缓存文件可能多达数MB,比如Google Maps,Market,浏览器和相册 程序,清理这几个程序的缓存文件就可以释放相当可观的空间。 ●很多手机厂商都在旗下手机预装了自己开发的UI程序,比如HTC Sense,MOTOBLUR等, 如果你打算使用LaunherPro或者ADW这样的launcher程序替代HTC Sense,你可以清理甚至删除HTC Sense的数据文件,这个操作可以让你的手机多出几十MB空间。 ●另外Android Market还提供一些自动清除缓存文件的应用程序,比如Quick App Clean Cache这款收费软件。对于已经取得root权限的手机用户,可以从Market下载CacheCleaner, CacheMate和MoveCache这些程序来快速方便的清除程序缓存文件。 删除那些你从来不用或者很少使用的应用程序 这是很多用户都会面对的问题,默默忍受着手机内存不足的报警,甚至牺牲系统性能,就是舍不得删除那些从来不用或者极少使用的应用程序,这可能也是一种强迫症。删除这些程序你会发现手机从此海阔天空,而且你没有任何损失。 移动所以可以移动的应用程序数据到SD

低端android机内存管理优化

大家好,今天我主要来和大家交流下低端android手机内存优化的问题。 一、问题的引出 前天,我在论坛发了一个帖子,想请教大家关于联想A68e内存优化的问题,但是回复者寥寥无几,课件也很少有机油对这方面有较深入的 学习了解。我今天中午,查了有关资料,也用了自己的手机进行了测试,觉得可能对A68e(其实是广大低端Android手机)用户有点帮助,所以特地来分享以下。(说明:本人用的是Sumsumg I9103,我媳妇用的是电信套餐的联想A68e,这几天我没拿到她的手机来测试,所以只能自己的手机进行测试,但是我觉得还是具有一定的参考价值的)。二、ROM和RAM 首先,我先解释一下ROM和RAM的区别。 ROM是Read Only Memory,即只读存储器;RAM是Access Random Memory,即随即读写存储器。 ROM是存储程序和数据的,类别电脑的硬盘,可以存放安装的程序、文件、数据等。而论坛中有开AppEXT2的方法(我没试过),那个只是节省出更多的ROM空间,这样可以使程序运行得更为流畅,但是不能解决“同时运行程序的数量最大值太小”的问题。以A68e为例,如果开一个QQ、音乐播放器,再开个UC浏览器估计机子就崩溃而导致程序退出。 RAM才是程序运行时所占用的物理空间。RAM的价格比ROM贵很多,所以RAM的大小一半程度上决定了机子的价位(另一半就是CPU)。

我的Sumsung是1G RAM,同时开QQ、QQ游戏、QQ音乐、浏览器、微信等七、八个程序也毫无压力。所以RAM太小是影响A68e(包括很多Android手机)用户体验的原因。如果你是个游戏玩家、手机达人,那么这类机子一定不适合你。如果你希望能像有高端机那样的用户体验,我建议你还是多话点银子购买配置高的Android手机。 关于官方宣传256的RAM实际上只有170,那是有一部分被Android系统占用。我的手机1GRAM,实际上也只有724M。 三、Android系统内存管理机制及进程调度机制 下面开始具体的分析了。 首先Android系统是基于Linux 内核开发的开源操作系统,li nux系统的内存管理有其独特的动态存储管理机制。Android采取了一种有别于Linux的进程管理策略,Linux系统在进程活动停止后就结束该进程,而Android把这些进程都保留在内存中,直到系统需要更多内存为止。这些保留在内存中的进程通常情况下不会影响整体系统的运行速度,并且当用户再次激活这些进程时,提升了进程的启动速度。 Android系统这样的设计不仅非常适合移动终端(手机、平板)的需要,而且减少了系统崩溃的可能,确保了系统的稳定性。老想着清理内存的同学完全是因为被塞班或者Windows毒害太深,事实上,经常用Taskiller之类的软件关闭后台所有进程,很容易造成系统的不稳定。很多时候出现问题了,只要重启就能解决的原因也在于此。 广大机油一定会发现,关闭了QQ、微信等程序后,其实并没有完全关闭这些程序。这些程序在后台占用了一定的内存,但是并没有运行时

Android中内存优化

Android中内存优化的那些事一个有关图片的优化记录 客服群里叫喊着:这个用户图片不显示了,那个用户图片也不显示了。我拿着手上一切正常的测试机,what the hell…… 默默地打开bugly。 满园春色关不住,遍地内存溢出来!是的,又闯祸了! 内存问题永远是既陌生又熟悉的话题,而且大多数都发生在一个叫作用户家的手机上。安卓系统本身不断的在优化,三方框架也逐渐成熟,外加手机厂商的大内存加持,似乎内存问题变得少见,但还是不能忽视。 借着这次修复内存问题的记录,分享一些“自以为”的解决思路,仅供参考。ok,let’s go! 修复问题的三部曲,先复现,再定位,最后修复。 复现 估计有的人会说,异常现象都在那,有啥好复现的,冲进代码直接开干。 修复bug永远是个惊心动魄的事,稍微一不小心就有可能天崩地裂。不是修复不完全,就是引入新问题。从起因开始了解整个缘由,一方面能加深对问题的理解,同时确保最终能验证问题是否得到修复。 内存的问题经常发生在一些比较特殊的环境下,而且很多时候不一定是必现,往往体现在一些中低端机型上。所以从机型上入手可能会是一个不错的选择。 最终,通过bugly查到了对应的问题机型及系统版本,上各类云测平台找到了台云测试机。按照进入问题页面的几个固定流程,反复执行,最终锁定了复现流程。

定位 知道问题如何复现,接下来就是定位问题到底出在哪。通常内存的问题,会碰到两种情况: 1.内存堆积:由于特殊情况造成的页面关闭但资源还遗漏在内存中。 2.内存高占用:由于业务需要或者使用不当导致内存占用量过高。 我们先来看看这次的问题属于哪种情况。 在Android Studio2.3及之前版本上自带的Android monitor中,可以直观的反应出当前应用的整体内存使用水平。[如何使用工具的分享估计大家都看腻了,这次就不再重复了。 142MB!!!!进入事故现场之前就已经被占用了这么多内存。难怪之后会内存异常。看来这次要先解决内存高占用的问题,我们先要详细的了解内存的具体情况,才知道从哪下手去解决,无论是避免无意义的使用或者优化必要的占用。 先强制gc一下,然后dump java heap,看一下整体内存里的情况,按照shallow size排序。 首当其冲的byte数组映入眼帘,大家都明白的,bitmap一直都是大客户。我们接着分析下byte[]中的各个对象。

Android内存使用研究

Android 内存使用研究 众所周知,在写 android 程序的时候,很容易出现 OOM ,而出现的时机大多数是由 Bitmap decode 引发的: 1 ERROR/AndroidRuntime(16350): https://www.sodocs.net/doc/0f14600925.html,ng.OutOfMemoryError: bitmap size exceeds VM budget 我们知道,android 程序内存一般限制在16M ,当然也有24M 的,而android 程序内存被分为2部分:native 和dalvik : dalvik 就是我们平常说的java 堆,我们创建的对象是在这里面分配的,而bitmap 是直接在native 上分配的,对于内存的限制是native+dalvik 不能超过最大限制。 注:一旦内存分配给Java 后,以后这块内存纵然开释后,也只能给Java 的施用,这个估计跟java 虚拟机里把内存分成好几块进行缓存的原因有关,反正C 就别想用到这块的内存了,所以要是Java 突然占用了一个大块内存,纵然很快开释了: C 能施用的内存 = 16M - Java 某一瞬间占用的最大内存。 而Bitmap 的生成是通过malloc 进行内存分配的,占用的是C 的内存,这个也就说明了,上面所说的的4MBitmap 无法生成的原因,因为在13M 被Java 用过后,剩下C 能用的只有3M 了。 用以下命令可以查看程序的内存使用情况: adb shell dumpsysmeminfopackagename orpid 程序的包名或者进程id

其中size是需要的内存,而allocated是分配了的内存,对应的2列分别是native和dalvik,当总数也就是total这一列超过单个程序内存的最大限制时,OOM就很有可能会出现了。 多数时候,发生OOM 都是在做一些跟图片相关的操作,以下提出一些建议尽量可以减少这种情况的发生: 1 .decode bitmap 的时候,尽量配置下Options,例如:inSameSize 2 .Bitmap使用完以后,调用 bitmap.recycle()来释放内存 3 .如果应用是基于图片的应用,尽量采用LazyLoad和DymanicRecycle 4.decode bitmap 的时候,将decode代码 try catch 出来,catch oom error,避免程序crash,可以在catch里面做一些释放内存操作 关于Android的Native内存和Dalvik内存 1.Dalvik内存 每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。 很多人认为Dalvik虚拟机是一个Java虚拟机,因为Android的编程语言恰恰就是Java语言。但是这种说法并不准确,因为 Dalvik虚拟机并不是按照Java 虚拟机的规范来实现的,两者并不兼容; 同时还要两个明显的不同: 1.Java虚拟机运行的是Java字节码,而Dalvik虚拟机运行的则是其专有的文件格式DEX(Dalvik Executable)。 2.在Java SE程序中的Java类会被编译成一个或者多个字节码文件(.class)然后打包到JAR文件,而后Java虚拟机会从相应的CLASS文件和JAR文件中获取相应的字节码;Android应用虽然也是使用Java语言进行编程,但是在编译成CLASS文件后,还会通过一个工具(dx)将应用所有的 CLASS文件转换成一个DEX文件,而后Dalvik虚拟机会从其中读取指令和数据。 Dalvik虚拟机的简介: Dalvik虚拟机主要是完成对象生命周期的管理,堆栈的管理,线程管理,安全和异常的管理,以及垃圾回收等等重要功能。 Dalvik虚拟机的主要特征Dalvik虚拟机非常适合在移动终端上使用,相对于在桌面系统和服务器系统运行的虚拟机而言,它不需要很快的CPU速度和大量的内存空间。 Dalvik虚拟机有如下几个主要特征: 1.专有的DEX文件格式 DEX是Dalvik虚拟机专用的文件格式,而问什么弃用已有的字节码文件(CLASS文件)而采用新的格式呢?一个应用中会定义很多类,编译完成后即会有很多相应的CLASS 文件,CLASS文件间会有不少冗余的信息;而DEX文件格式会把所有的CLASS文件内容整合到一个文件中。这样,除了减少整体的文件尺寸,I/O操作,也提高了类的查找速度。 2.增加了新的操作码的支

android系统详细介绍

android Android一词的本义指“机器人”,同时也是Google于2007年11月5日宣布的基于Linu x平台的开源手机操作系统的名称,该平台由操作系统、中间件、用户界面和应用软件组成,号称是首个为移动终端打造的真正开放和完整的移动软件。目前最好的是Android2.0的摩托罗拉Droid 目录[显示] [编辑本段] 简介 Android是基于Linux内核的软件平台和操作系统,早期由Google开发,后由开放手机联盟(Open Handset Alliance)开发。它采用了软件堆层(software st ack,又名为软件叠层)的架构,主要分为三部分。底层以Linux内核工作为基础,只提供基本功能;其他的应用软件则由各公司自行开发,以Java作为编写程序的一部分。另外,为了推广此技术,Google和其它几十个手机公司建立了开放手机联盟。Android在未公开之前常被传闻为Google电话或gPhone。大多传闻认为Goog le开发的是自己的手机电话产品,而不是一套软件平台。到了2010年1月,Googl e开始发表自家品牌手机电话的NexusOne。目前最新版本为Android2.1。 对手机行业的影响 已经与HTC、NTT DoCoMo、KDDI、Motorola等世界移动领域34家公司于免费提供达成一致。今后对于移动通讯的影响势必会进一步体现出来。但是如此广泛公司的同盟是否能够有效运作以及持久,让我们拭目以待。 Android手机 2008年9月22日,美国运营商T-MobileUSA在纽约正式发布第一款Goog le手机——T-Mobile G1。该款手机为台湾宏达电代工制造,是世界上第一部使用Android操作系统的手机,支持WCDMA/HSPA网络,理论下载速率7.2Mbps,并支持Wi-Fi。 (左图为Androidlogo) [编辑本段]

Android内存分配小结

有Android手机的童鞋们可能经常会有这样的疑问,为什么我的G2手机明明是256M的内存,可用任务管理器或者free之类的命令,看到的实际值会远远小于256。看到网上的很多误导言论,这里我给大家澄清一下吧: 无图无真相,贴张MSM7627的内存分布图,一目了然: 由上图可以看到,内存主要分给modem/bootloader/SMEM/pmem/Android几个部分使用: 1、modem/bootloader/SMEM部分一般会占用40M~50M的内存,上图占用了43M。这部分主要用于跑AMSS、bootloader及RPC。如果你有源码的话,可以在 device\qcom\msmxxx/Boardconfig.mk看到。还有一种方法,可以用adb pull /proc/config.gz .将config.gz文件dump下来,里面可以看到分配给linux的内存大小,用物理内存总大小减去这部分,就可以得到这部分的内存总开销。 2、Pmem一般会占用40M的内存,上图占用了38M左右。系统的framebuffer\mdp\video 等都会用到这部分memory。如果你有源码的话,可以在

kernel/arch/arm/mach-msm/Board-xxx.c文件中看到Pmem的分配情况。譬如:#define MSM_PMEM_MDP_SIZE 0x1B76000 #define MSM_PMEM_ADSP_SIZE 0xAE4000 #define MSM_PMEM_AUDIO_SIZE 0x5B000 #define MSM_FB_SIZE 0x177000 #define MSM_GPU_PHYS_SIZE 0x177000 #define PMEM_KERNEL_EBI1_SIZE 0x1C000 3、最后是给用户空间使用的memory,用free或者cat /proc/meminfo等命令看到的是这部分的memory大小。大小是之前第一步传给linux kernel的memory大小减去pmem的占用部分再减去linux kernel和ramdisk大小。 本篇文章来源于Linux公社网站(https://www.sodocs.net/doc/0f14600925.html,) 原文链接: https://www.sodocs.net/doc/0f14600925.html,/Linux/2010-11/29891.htm

android内存优化详解

Android内存优化详解 Android内存泄露 前言 不少人认为JAVA程序,因为有垃圾回收机制,应该没有内存泄露。 其实如果我们一个程序中,已经不再使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成了内存泄露。如果我们的java运行很久,而这种内存泄露不断的发生,最后就没内存可用了。当然java的,内存泄漏和C/C++是不一样的。如果java程序完全结束后,它所有的对象就都不可达了,系统就可以对他们进行垃圾回收,它的内存泄露仅仅限于它本身,而不会影响整个系统的。C/C++的内存泄露就比较糟糕了,它的内存泄露是系统级,即使该C/C++程序退出,它的泄露的内存也无法被系统回收,永远不可用了,除非重启机器。 Android的一个应用程序的内存泄露对别的应用程序影响不大。为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的。Android为不同类型的进程分配了不同的内存使用上限,如果程序在运行过程中出现了内存泄漏的而造成应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉,这使得仅仅自己的进程被kill掉,而不会影响其他进程(如果是 system_process等系统进程出问题的话,则会引起系统重启)。 1,引用没释放造成的内存泄露 1.1注册没取消造成的内存泄露 这种Android的内存泄露比纯java的内存泄露还要严重,因为其他一些Android程序可能引用我们的Anroid程序的对象(比如注册机制)。即使我们的Android程序已经结束了,但是别的引用程序仍然还有对我们的Android程序的某个对象的引用,泄露的内存依然不能被垃圾回收。 比如示例1: 假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。 但是如果在释放LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener 对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得 system_process进程挂掉。

相关主题