要测内存泄漏呢,可以反复进入某一项操作,如反复进入联系人详情后返回键,观察内存的值是否有上升的趋势。
测试方法:
1.创建自动化测试脚本,每操作一次获取一次内存值,然后把内存值导出到文件中,制作成曲线图,就可以很直观的看见是否存在内存泄漏了。曾经用Uiautomator做过一次内存泄漏的脚本,如下:
package demotest; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import com.android.uiautomator.core.UiObject; import com.android.uiautomator.core.UiObjectNotFoundException; import com.android.uiautomator.core.UiScrollable; import com.android.uiautomator.core.UiSelector; import com.android.uiautomator.testrunner.UiAutomatorTestCase; public class MemoryLeak extends UiAutomatorTestCase { // 应用包名 static final String packageName = "com.android.phone"; // 测试次数 static final int counts = 500; public static void main(String[] args) { String jarName, testClass, testName, androidId; jarName = "demotest"; testClass = "demotest.MemoryLeak"; testName = "testScene_03"; androidId = "3"; new UiAutomatorHelper(jarName, testClass, testName, androidId); } // 场景一:打开/退出联系人 public void testScene_01() throws IOException { File mTxt = mkFile("01");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); for (int i = 0; i < counts; i++) { scene_01();// 执行场景一的case sleep(2000);// 延迟2s String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); } //场景二:查看联系人 public void testScene_02() throws IOException { File mTxt = mkFile("02");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); scene_01();//打开联系人 for(int i=0;i<counts;i++) { getUiDevice().click(334, 416); sleep(1000); getUiDevice().pressBack(); String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); getUiDevice().pressBack(); // 退出联系人 } //添加联系人 public void testScene_03() throws IOException, UiObjectNotFoundException { File mTxt = mkFile("03");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); scene_01();//打开联系人 for(int i=0;i<counts;i++) { UiObject add=new UiObject(new UiSelector().resourceId("com.aurora:id/aurora_action_bar_item")); add.clickAndWaitForNewWindow(); UiObject name=new UiObject(new UiSelector().text("请输入姓名")); name.setText("penghong"); sleep(500); UiObject number=new UiObject(new UiSelector().text("请输入号码")); number.setText("15079034630"); sleep(1000); new UiObject(new UiSelector().text("确定")).clickAndWaitForNewWindow(); getUiDevice().pressBack(); sleep(2000);// 延迟2s String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); getUiDevice().pressBack(); getUiDevice().pressBack(); } //删除联系人 public void testScene_04() throws IOException, UiObjectNotFoundException { File mTxt = mkFile("04");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); scene_01();//打开联系人 for(int i=0;i<counts;i++) { getUiDevice().swipe(550,395,215,402,40); sleep(1000); new UiObject(new UiSelector().resourceId("com.aurora:id/aurora_rubbish")).clickAndWaitForNewWindow(); new UiObject(new UiSelector().text("确定")).clickAndWaitForNewWindow(); sleep(500); String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); getUiDevice().pressBack(); } // 场景一:打开/退出拨号盘 public void testScene_05() throws IOException { File mTxt = mkFile("05");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); for (int i = 0; i < counts; i++) { scene_001(); sleep(2000);// 延迟2s String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); } //拨号盘中界面切换 public void testScene_06() throws IOException { File mTxt = mkFile("06");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); scene_001(); for(int i=0;i<counts;i++) { getUiDevice().click(134, 1230); sleep(500); getUiDevice().click(373, 1248); sleep(500); getUiDevice().click(630, 1250); sleep(500); String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); getUiDevice().pressBack(); } //反复进入电话帮 public void testScene_07() throws IOException { File mTxt = mkFile("07");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); scene_001(); for(int i=0;i<counts;i++) { getUiDevice().click(373, 1248); sleep(500); String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); getUiDevice().pressBack(); } //拨号盘搜索联系人 public void testScene_08() throws IOException, UiObjectNotFoundException { File mTxt = mkFile("08");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); scene_001(); getUiDevice().click(386, 1223); sleep(500); if(new UiObject(new UiSelector().resourceId("com.android.contacts:id/yulore_superyellowpage_et_search")).exists()) { getUiDevice().click(386, 1223); sleep(500); } for(int i=0;i<counts;i++) { new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_one")).click(); new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_three")).click(); new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_zero")).click(); new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_deleteButton")).longClick(); String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); getUiDevice().pressBack(); } //拨号盘呼叫 public void testScene_09() throws IOException, UiObjectNotFoundException { File mTxt = mkFile("09");// 创建文件 FileOutputStream fos = null;// 以字节流的形式读取 fos = new FileOutputStream(mTxt); scene_001(); getUiDevice().click(386, 1223); sleep(500); if(new UiObject(new UiSelector().resourceId("com.android.contacts:id/yulore_superyellowpage_et_search")).exists()) { getUiDevice().click(386, 1223); sleep(500); } for(int i=0;i<counts;i++) { new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_one")).click(); new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_zero")).click(); new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_zero")).click(); new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_eight")).click(); new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_six")).click(); new UiObject(new UiSelector().resourceId("com.android.contacts:id/aurora_dialButton")).click(); sleep(3000); new UiObject(new UiSelector().text("结束通话")).clickAndWaitForNewWindow(); String mMemory = memory(packageName);// 读取每一次的memory sleep(2000); byte[] b1 = (mMemory + "\n").getBytes(); fos.write(b1); } fos.close(); getUiDevice().pressBack(); } //打开联系人 public void scene_01() { getUiDevice().pressHome(); UiScrollable deckViews = new UiScrollable( new UiSelector().scrollable(true)); deckViews.setAsHorizontalList(); UiObject sApp; try { sApp = deckViews .getChildByText( new UiSelector() .className(android.widget.TextView.class .getName()), "联系人"); sApp.clickAndWaitForNewWindow(); } catch (UiObjectNotFoundException e) { e.printStackTrace(); } //getUiDevice().pressBack(); } //打开拨号盘 public void scene_001() { getUiDevice().pressHome(); UiScrollable deckViews = new UiScrollable( new UiSelector().scrollable(true)); deckViews.setAsHorizontalList(); UiObject sApp; try { sApp = deckViews .getChildByText( new UiSelector() .className(android.widget.TextView.class .getName()), "拨号"); sApp.clickAndWaitForNewWindow(); } catch (UiObjectNotFoundException e) { e.printStackTrace(); } //getUiDevice().pressBack(); } // 读取每一次的内存值 public String memory(String packageName) { Process proc = null; StringBuffer sb = new StringBuffer(); String line, Pss = null; try { proc = Runtime.getRuntime().exec("dumpsys meminfo " + packageName); proc.waitFor(); BufferedReader br = new BufferedReader(new InputStreamReader( proc.getInputStream())); while ((line = br.readLine()) != null) { if (line.contains("TOTAL")) { sb.append(line + "\n"); } } String[] s = sb.toString().split("TOTAL"); String s2 = s[1].trim(); String[] s3 = s2.split(" "); Pss = s3[0].trim(); System.out.println("***调试开始***"); System.out.println(sb.toString());// 打印字符串 System.out.println(Arrays.toString(s));// 打印数组 System.out.println(s2); System.out.println(Arrays.toString(s3)); System.out.println("Pss=" + Pss); System.out.println("***调试完成***"); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return Pss; } // 格式化时间 public String formatDate() { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHms"); String time = sdf.format(date); return time; } // 创建文件保存日志 public File mkFile(String casename) { String path = "/storage/sdcard0/uiautomator/memory"; String file = path + "/Scene_"+casename + formatDate() + ".log"; File filePath = new File(path); File txt = new File(file); if (!filePath.exists() && !txt.exists()) { filePath.mkdirs(); try { txt.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } return txt; } }
2.用 bat脚本连续读取应用程序的内存使用情况(一边操作一边观察内存值是否一直上升)
set process=com.android.contacts @adb shell dumpsys meminfo %process% | findstr "Pss" :m @adb shell dumpsys meminfo %process% | findstr "TOTAL" @ping -n 5 127.1>nul @goto m
3.用eclipse中的DDMS
手动连电脑,选中要测试的进程名--点击Update help--操作应用的同时观察右边Heap区域的total size是否会一直上升,在此期间可以点击GC按扭触发android垃圾回收
如果一直呈上升趋势则点击Dump HPROF按扭把内存映像拷贝下来,然后用MAT工具去分析。
时间: 2024-10-30 19:07:12