MAT基础知识

MAT简介

MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。 
这里写图片描述

当然MAT也有独立的不依赖Eclipse的版本,只不过这个版本在调试Android内存的时候,需要将DDMS生成的文件进行转换,才可以在独立版本的MAT上打开。不过Android SDK中已经提供了这个Tools,所以使用起来也是很方便的。

MAT工具的下载安装

这里是MAT的下载地址:https://eclipse.org/mat/downloads.php,下载时会提供三种选择的方式: 
这里写图片描述

  • Update Site 这种方式后面会有一个网址:比如http://download.eclipse.org/mat/1.4/update-site/ ,安装过Eclipse插件的同学应该知道,只要把这段网址复制到对应的Eclipse的Install New Software那里,就可以进行在线下载了。 
    这里写图片描述

  • Archived Update Site 这种方式安装的位置和上一种差不多,只不过第一种是在线下载,这一种是使用离线包进行更新,这种方式劣势是当这个插件更新后,需要重新下载离线包,而第一种方式则可以在线下载更新。

  • Stand-alone Eclipse RCP Applications 这种方式就是把MAT当成一个独立的工具使用,不再依附于Eclipse,适合不使用Eclipse而使用Android Studio的同学。这种方式有个麻烦的地方就是DDMS导出的文件,需要进行转换才可以在MAT中打开。

下载安装好之后,就可以使用MAT进行实际的操作了。

MAT中一些概念介绍

要看懂MAT的列表信息,Shallow heap、Retained Heap、GC Root 这几个概念一定要弄懂。

1、Shallow heap

Shallow size就是对象本身占用内存的大小,不包含其引用的对象。

  1. 常规对象(非数组)的Shallow size有其成员变量的数量和类型决定。
  2. 数组的shallow size有数组元素的类型(对象类型、基本类型)和数组长度决定 
    因为不像c++的对象本身可以存放大量内存,java的对象成员都是些引用。真正的内存都在堆上,看起来是一堆原生的byte[],char[], int[],所以我们如果只看对象本身的内存,那么数量都很小。所以我们看到Histogram图是以Shallow size进行排序的,排在第一位第二位的是byte,char 。

2、Retained Heap

Retained Heap的概念,它表示如果一个对象被释放掉,那么该对象引用的所有对象(包括被递归释放的)占用的heap也会被释放。 
举例: 
如果一个对象的某个成员new了一大块int数组,那这个int数组也可以计算到这个对象中。与shallow heap比较,Retained heap可以更精确的反映一个对象实际占用的大小(因为如果该对象释放,retained heap都可以被释放)。

Retained Heap并不总是那么有效。 
举例:

  1. 我在A里new了一块内存,赋值给A的一个成员变量。

  2. 我让B也指向这块内存。

    此时,因为A和B都引用到这块内存,所以A释放时,该内存不会被释放。所以这块内存不会被计算到A或者B的Retained Heap中。

为了纠正这点,MAT中的Leading Object(例如A或者B)不一定只是一个对象,也可以是多个对象。此时,(A,B)这个组合的Retained Set就包含那块大内存了。对应到MAT的UI中,在Histogram中,可以选择Group By class, superclass or package来选择这个组。

为了计算Retained Memory,MAT引入了Dominator Tree

举例:

  • 对象A引用B和C,B和C又都引用到D(一个菱形)。

  • 计算Retained Memory

    • A的包括A本身和B,C,D。
    • B和C因为共同引用D,所以B,C 的Retained Memory都只是他们本身。
    • D当然也只是自己。

在这里例子中,树根是A,而B,C,D是他的三个儿子。B,C,D不再有相互关系。

我觉得是为了加快计算的速度,MAT将对象引用图转换成对象引用树。把引用图变成引用树,计算Retained Heap就会非常方便,显示也非常方便。对应到MAT UI上,在dominator tree这个view中,显示了每个对象的shallow heap和retained heap。然后可以以该节点为树根,一步步的细化看看retained heap到底是用在什么地方了。

这种从图到树的转换确实方便了内存分析,但有时候会让人有些疑惑。本来对象B是对象A的一个成员,但因为B还被C引用,所以B在树中并不在A下面,而很可能是平级。

为了纠正这点,MAT中点击右键,可以List objects中选择with outgoing references和with incoming references。这是个真正的引用图的概念,

  • outgoing references :表示该对象的出节点(被该对象引用的对象)。
  • incoming references :表示该对象的入节点(引用到该对象的对象)。

为了更好地理解Retained Heap,下面引用一个例子来说明:

把内存中的对象看成下图中的节点,并且对象和对象之间互相引用。这里有一个特殊的节点GC Roots,这就是reference chain(引用链)的起点: 
这里写图片描述 
这里写图片描述

从obj1入手,上图中蓝色节点代表仅仅只有通过obj1才能直接或间接访问的对象。因为可以通过GC Roots访问,所以上图的obj3不是蓝色节点;而在下图却是蓝色,因为它已经被包含在retained集合内。

  • 上图中obj1的retained size是obj1、obj2、obj4的shallow size总和;
  • 下图的retained size是obj1、obj2、obj3、obj4的shallow size总和。 
    obj2的retained size是obj3、obj4的shallow size总和。

3、GC Root

  • GC发现通过任何reference chain(引用链)无法访问某个对象的时候,该对象即被回收。

名词GC Roots正是分析这一过程的起点,例如JVM自己确保了对象的可到达性(那么JVM就是GC Roots),所以GC Roots就是这样在内存中保持对象可到达性的,一旦不可到达,即被回收。

通常GC Roots是一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量),或者是线程自身或者是system class loader(系统类加载器)加载的类以及native code(本地代码)保留的活动对象。所以GC Roots是分析对象为何还存活于内存中的利器。

MAT主界面介绍

这里介绍的不是MAT这个工具的主界面,而是导入一个文件之后,显示OverView的界面。

一、打开经过转换的hprof文件:

这里写图片描述

如果选择了第一个,则会生成一个报告。这个无大碍。

这里写图片描述

二、 选择OverView界面:

这里写图片描述

我们需要关注的是下面Actions区域,介绍4种分析方法:

  1. Histogram:列出内存中的对象,对象的个数以及大小

    这里写图片描述

  2. Dominator Tree:列出最大的对象以及其依赖存活的Object (大小是以Retained Heap为标准排序的) 
    这里写图片描述

  3. Top Consumers : 通过图形列出最大的object 
    这里写图片描述

  4. Duplicate Class:通过MAT自动分析泄漏的原因

一般Histogram和 Dominator Tree是最常用的。

三、打开default_report窗口。

该窗口列出了,可能有问题的代码片段。点击Details可以查看相关的详情。 
这里写图片描述

  1. 在Shortest Paths To the Accumulation Point的列表中,我们可以追溯到问题代码的类树的结构,并找到自己代码中的类。 
    在列表中,有两列Shallow Heap和Retained Heap。Shallow Heap指的是所有的实例的内存总和。Retained Heap指的是所有类实例被分配的内存总和,里面包括它们所有引用的对象。 
    这里写图片描述

  2. 在Accumulated Objects列表中,我们可以看见创建的大量的对象。 
    这里写图片描述

  3. 在Accumulated Objects by Class列表中,我们能看见创建大量对象相关的类。 
    这里写图片描述

MAT中的一些有用的视图

1、Thread OvewView

Thread OvewView可以查看这个应用的Thread信息: 
这里写图片描述

2、Group

在Histogram和Domiantor Tree界面,可以选择将结果用另一种Group的方式显示(默认是Group by Object),切换到Group by package,可以更好地查看具体是哪个包里的类占用内存大,也很容易定位到自己的应用程序。 
这里写图片描述

3、Path to GC Root

在Histogram或者Domiantor Tree的某一个条目上,右键可以查看其GC Root Path:

这里写图片描述

点击Path To GC Roots –> with all references 
这里写图片描述

这里也要说明一下Java的引用规则: 
从最强到最弱,不同的引用(可到达性)级别反映了对象的生命周期。

  • Strong Ref(强引用):通常我们编写的代码都是Strong Ref,于此对应的是强可达性,只有去掉强可达,对象才被回收。

  • Soft Ref(软引用):对应软可达性,只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有Strong Ref时才回收对象。一般可用来实现缓存,通过java.lang.ref.SoftReference类实现。

  • Weak Ref(弱引用):比Soft Ref更弱,当发现不存在Strong Ref时,立刻回收对象而不必等到内存吃紧的时候。通过java.lang.ref.WeakReference和java.util.WeakHashMap类实现。

  • Phantom Ref(虚引用):根本不会在内存中保持任何对象,你只能使用Phantom Ref本身。一般用于在进入finalize()方法后进行特殊的清理过程,通过 java.lang.ref.PhantomReference实现。
<think>嗯,用户想了解Excel中的VLOOKUP函数的用法和参数含义。首先,我需要回忆一下VLOOKUP的基本结构。VLOOKUP是垂直查找函数,用于在表格的首列查找指定的值,然后返回该行中指定列的数据。它的四个参数分别是查找值、表格范围、列索引号和匹配模式。 接下来,我得确认每个参数的具体作用。第一个参数是lookup_value,也就是用户要查找的值,比如产品ID或者姓名。第二个参数是table_array,即查找的范围,这里要注意的是,查找值必须位于这个范围的第一列,否则函数无法正确工作。第三个参数是col_index_num,也就是用户想要返回的数据在表格范围中的第几列,这个列数是从表格范围的第一列开始算起的,不是整个工作表的列。第四个参数是range_lookup,决定是精确匹配还是近似匹配,通常用FALSE或0来指定精确匹配,避免错误。 然后,用户可能需要一个具体的例子来理解如何使用。比如,假设有一个产品价格表,用户想根据产品ID查找对应的价格。这时候,VLOOKUP就可以在ID列查找,然后返回价格列的数据。同时,要提醒用户注意表格范围最好使用绝对引用,比如$A$2:$C$100,这样在拖动公式时范围不会变化。 可能遇到的问题也需要考虑。比如,如果查找值不在表格的第一列,或者列索引号超过了表格的列数,函数会返回错误。此外,数据格式不一致也可能导致问题,比如查找值是数字,而表格中是文本格式的数字,这时候需要统一格式。还有,当出现#N/A错误时,可能是查找值不存在,或者匹配模式设置不正确,需要检查参数是否正确。 用户可能还会问到如何避免常见的错误,比如部分数据匹配出错的情况。这时候需要检查是否有多余的空格,或者数据格式不一致,或者表格范围没有锁定导致拖动时偏移。此外,XLOOKUP作为VLOOKUP的升级版,可能在某些情况下更方便,比如可以向左查找或者返回多列数据,这也是可以提及的内容。 最后,整理步骤,从基础语法到参数说明,再到具体案例,逐步引导用户理解如何使用VLOOKUP函数。同时,提供常见错误和解决方法,帮助用户在实际应用中避免问题。如果有必要,还可以比较VLOOKUP和其他查找函数的区别,比如HLOOKUP或XLOOKUP,但根据用户的问题,主要集中在VLOOKUP本身即可。</think>### Excel VLOOKUP函数详解 #### 一、基础语法与参数说明 VLOOKUP函数的语法为: $$=VLOOKUP(lookup\_value, table\_array, col\_index\_num, [range\_lookup])$$ 包含4个参数: 1. **lookup_value**(必填):要查找的值(如单元格引用或具体值) 2. **table_array**(必填):包含数据的表格范围(必须包含查找列和返回列) 3. **col_index_num**(必填):返回值所在列的序号(从table_array第一列开始计数) 4. **range_lookup**(可选):匹配类型 - `TRUE`/`1`:近似匹配(默认值,需数据升序排列) - `FALSE`/`0`:精确匹配(常用选项) [^1][^2] #### 二、使用步骤演示(工资表查询案例) 假设需要根据员工编号查询工资: 1. 建立查询单元格(如`B12`) 2. 输入公式: ```excel =VLOOKUP(A12, $A$2:$D$100, 4, 0) ``` - `A12`:待查询的员工编号 - `$A$2:$D$100`:锁定数据区域(绝对引用) - `4`:返回第4列(工资列) - `0`:精确匹配 [^2][^3] #### 三、常见错误与解决方法 | 错误现象 | 原因 | 解决方案 | |---------|------|---------| | #N/A | 查找值不存在 | 检查数据源或改用`IFERROR`容错 | | #REF! | 列序号超出范围 | 确认col_index_num ≤ 表格列数 | | 部分匹配失败 | 数据格式不一致 | 统一数值/文本格式 | | 结果错位 | 表格未锁定 | 使用`$`符号固定区域引用 | [^3][^4] #### 四、进阶技巧 1. **多条件查询**: 使用辅助列合并多个条件字段 ```excel =VLOOKUP(A2&B2, $D$2:$F$100, 3, 0) ``` 2. **通配符匹配**: `"*"`匹配任意字符,`"?"`匹配单个字符 ```excel =VLOOKUP("张*", $A$2:$C$100, 3, 0) ``` 3. **跨表查询**: 引用其他工作表数据 ```excel =VLOOKUP(A2, Sheet2!$A$2:$D$100, 4, 0) ``` [^1][^4]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值