- GC_EXTERNAL_ALLOC:这是为external分配的内存执行的GC,也就是上文提到的Bitmap Pixel Data之类的。
- GC_HPROF_DUMP_HEAP:这是当你做HPROF这样一个操作去创建一个HPROF profile的时候执行的。
- GC_EXPLICIT:这是由于你显式的调用了System.gc(),这是不提倡的,一般来说我们可以信任系统的GC。
freed 2049K表明在这次GC中回收了多少内存。
65% free 3571K/9991K是heap的一些统计数据,表明这次回收后65%的heap可用,存活的对象大小3571K,heap大小是9991K。
external 4703K/5261K是Native Memory的数据。放Bitmap Pixel Data或者是NIO Direct Buffer之类的。第一个数字表明Native Memory中已分配了多少内存,第二个值有点类似一个浮动的阀值,表明分配内存达到这个值系统就会触发一次GC进行内存回收。
paused 2ms 2ms表明GC暂停的时间。从这里你可以看到越大的heap size你需要暂停的时间越长。如果是concurrent gc你会看到2个时间一个开始一个结束,这时间是很短的,但如果是其他类型的GC,你很可能只会看到一个时间,而这个时间是相对比较长的。
通过Log可以对内存信息有个基本的了解,但这不足以了解什么对象在使用内存,在哪使用了内存。这时候你需要用Heap Dumps。一个Heap Dump基本上来说就是一个包含你heap中所有对象信息的二进制文件。你可以用DDMS来生成这个文件,点击DDMS中下图的那个按钮。
同时Heap Dumps也有对应的API,你想要在特定的时间点获取一份Heap Dump,使用android.os.Debug.dumpHprofData()。获取到的文件要转换成标准的HPROF格式,使用如下命令:hprof-conv orig.hprof converted.hprof。然后用MAT或者jhat进行分析。
在讲MAT之前先讲下Memory Leaks。要清楚GC并不能防止Memory Leaks,所谓Memory Leaks就是引用到了已经没用的对象从而让这些对象避免了被GC回收,跟C/C++中的概念并不一样。容易导致内存泄漏的是一些Activity,Context,View,Drawable之类的引用,和一些非静态的内部类比方说Runnable之类的以及一些Caches。比如你旋转屏幕的时候在新的方向上产生一个新的Activity,如果有变量引用到旧的Activity就会导致其无法被GC,造成Memory Leaks。
通常通过上面介绍的Log信息,只要已用memory一直处于上升的情形而不回落,便大致能了解到应用存在Memory Leaks。不过MAT这类工具可以帮助你更好的对memory进行分析。使用MAT之前有2个概念是要掌握的:Shallow heap和Retained heap。Shallow heap表示对象本身所占内存大小,一个内存大小100bytes的对象Shallow heap就是100bytes。Retained heap表示通过回收这一个对象总共能回收的内存,比方说一个100bytes的对象还直接或者间接地持有了另外3个100bytes的对象引用,回收这个对象的时候如果另外3个对象没有其他引用也能被回收掉的时候,Retained heap就是400bytes。
MAT使用Dominator Tree这样一种来自图形理论的概念。
所谓Dominator,就是Flow Graph中从源节点出发到某个节点的的必经节点。那么根据这个概念我们可以从上图左侧的Flow Graph构造出右侧的Dominator Tree。这样一来很容易就看出每个节点的Retained heap了。Shallow heap和Retained heap在MAT中是非常有用的概念,用于内存泄漏的分析。
我们用Honeycomb3.0中的HoneycombGallery做一个Demo。在工程的MainActivity当中加入如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class MainActivity extends Activity implements ActionBar.TabListener {
static Leaky leak = null;
class Leaky {
void doSomething() {
System.out.println("Wheee!!!");
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (leak == null) {
leak = new Leaky();
}
...
|
原文转自:http://my.eoe.cn/futurexiong/archive/1299.html