本人在最近手機APP性能數據的過程當中,又從新看了一些Android的內存相關知識,對以前寫過的一篇APP性能的線程類的方法作了優化,總得來講,就是增長了PSS數據和增長了數據獲取以後的數據整理工做。java
獲取PSS的方法原理是經過adb shell dumpsys命令獲取到的,以前放棄了這個方法,由於內存數據太細分了,後來發現細分的更準確。這裏沒有統計Native Heap和Dalvik Heap,感受統計數據的話並無多大的必要。對這塊也不是很是瞭解若是有不對的地方,還請指正。sql
方法以下:shell
/** * 獲取應用信息 利用Android系統dumpsys命令獲取 * 命令能統計到java虛擬的堆內存和棧內存的使用狀況 * * @return 返回內存佔用 */ public int getMemResult() { String cmd1 = Common.ADB_PATH + "adb shell dumpsys meminfo " + package_name; int mem_result = 0; try { Process p = Runtime.getRuntime().exec(cmd1);// 經過runtime類執行cmd命令 // 正確輸出流 InputStream input = p.getInputStream();// 建立並實例化輸入字節流 BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容 String line = ""; while ((line = reader.readLine()) != null) {// 循環讀取 if (line.startsWith(" TOTAL")) { mem_result = getMemInfo(line); } } reader.close();// 此處reader依賴於input,應先關閉 input.close(); // 錯誤輸出流 InputStream errorInput = p.getErrorStream();// 建立並實例化輸入字節流 BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorInput));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容 String eline = ""; while ((eline = errorReader.readLine()) != null) {// 循環讀取 System.out.println(eline);// 輸出 } errorReader.close();// 此處有依賴關係,先關閉errorReader errorInput.close(); } catch (IOException e) { output("執行" + cmd1 + "失敗!", e); } return mem_result; }
下面是增長的統計方法,主要是在每次新建進程的時候都會記錄一個mark,統計方法寫在結束線程的方法裏:數據庫
public void stopRecord() { AppLocalMySql.getInstance().ClearUpPerformaceData(mark);//整理數據 PerformanceThread.key = false;//結束線程 }
/** * 整理一次性能數據收集 * * @param mark * 統計mark */ public void ClearUpPerformaceData(int mark) { getConnection(); int cpu = 0, pss = 0, rss = 0, vss = 0, total = 0; String device = null, packages = null, test_name = null; try { if (!connection.isClosed()) { outputSuccess(); Statement statement = connection.createStatement(); String sql = "SELECT AVG(cpu),AVG(pss),AVG(rss),AVG(vss),COUNT(*),device,package,test_name FROM app_result WHERE mark = " + mark; ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()) { cpu = resultSet.getInt(1); pss = resultSet.getInt(2); rss = resultSet.getInt(3); vss = resultSet.getInt(4); total = resultSet.getInt(5); device = resultSet.getString("device"); packages = resultSet.getString("package"); test_name = resultSet.getString("test_name"); } String sql2 = "INSERT INTO app_report (mark,test_name,package,device,cpu,pss,rss,vss,total) VALUES (" + mark + ",'" + test_name + "','" + packages + "','" + device + "'," + cpu + "," + pss + "," + rss + "," + vss + "," + total + ")"; statement.executeUpdate(sql2); statement.close(); connection.close(); } } catch (SQLException e) { output("統計方法出錯!", e); } }
多線程實現:編程
package source; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author ··-·塵 * @E-mail:Fhaohaizi@163.com * @version 建立時間:2017年8月23日 下午2:56:22 * @alter 修改時間:2017年8月24日 10:02:19 類說明:測試內存和cpu信息 */ public class PerformanceThread extends Thread { public int mark = Common.getInstance().getMark(); public static boolean key = true; public static String device_id; public static String package_name; public static String test_name; // 建立實例 private static PerformanceThread performanceTest; @Override public void run() { while (key) {// 循環執行該方法 try { sleep(15 * 1000);// 線程休眠 } catch (InterruptedException e) { e.printStackTrace();// 打印異常 } getCpuAndMemDate();// 執行手機數據的方法 } } public static PerformanceThread getInstance() { if (performanceTest == null) { performanceTest = new PerformanceThread(); } return performanceTest; } public PerformanceThread() { getDevicesId(); PerformanceThread.package_name = Common.PAGEKAGE; output("歡迎使用手機性能監控線程!"); } public PerformanceThread(String package_name) { getDevicesId(); PerformanceThread.package_name = package_name; output("歡迎使用手機性能監控線程!"); } public PerformanceThread(String testname, String package_name) { getDevicesId(); PerformanceThread.package_name = package_name; PerformanceThread.test_name = testname; output("歡迎使用手機性能監控線程!"); } /** * 結束線程方法 */ public void stopRecord() { AppLocalMySql.getInstance().ClearUpPerformaceData(mark); PerformanceThread.key = false; } /** * 獲取devicesID */ public void getDevicesId() { String cmd = "adb devices"; String OSname = System.getProperty("os.name"); try { Process p = null; if (OSname.contains("Mac")) { p = Runtime.getRuntime().exec(Common.ADB_PATH + cmd); } else { p = Runtime.getRuntime().exec("cmd /c " + cmd); } // 正確輸出流 InputStream input = p.getInputStream();// 建立並實例化輸入字節流 BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容 String line = ""; while ((line = reader.readLine()) != null) {// 循環讀取 if (line.contains("device")) { PerformanceThread.device_id = line.replaceAll("device", ""); } // System.out.println(line);// 輸出 } reader.close();// 此處reader依賴於input,應先關閉 input.close(); } catch (IOException e) { output("執行" + cmd + "失敗!"); e.printStackTrace(); } } /** * 獲取cpu和mem數據,此方法用的是top命令 */ public void getCpuAndMemDate() { int pss = getMemResult();// 獲取內存數據 int[] result = getPerformanceResult();// 獲取數據 int cpu_result = result[0];// 獲取cpu int vss = result[1];// 獲取虛擬內存數據 int rss = result[2];// 獲取物理內存數據 output("CPU:" + cpu_result, "VSS:" + vss, "RSS:" + rss, "PSS:" + pss); AppLocalMySql.getInstance().saveMemAndCpuResult(mark, package_name, device_id, cpu_result, vss, rss, pss, test_name);// 寫入數據庫 } /** * 獲取統計結果 利用Linux系統top命令 -m表示個數,-n表示獲取次數此處寫爲1 * * @return 返回int數組,包含rss,vss,cpu百分比 */ public int[] getPerformanceResult() { String cmd = Common.ADB_PATH + "adb shell top -m 8 -n 1"; int cpu_result = 0, vss = 0, rss = 0; try { Process p = Runtime.getRuntime().exec(cmd);// 經過runtime類執行cmd命令 // 正確輸出流 InputStream input = p.getInputStream();// 建立並實例化輸入字節流 BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容 String line = ""; while ((line = reader.readLine()) != null) {// 循環讀取 if (line.contains(package_name)) {// 獲取行 cpu_result = getCpuDate(line); vss = getVss(line); rss = getRss(line); } } reader.close();// 此處reader依賴於input,應先關閉 input.close();// 關閉流 // 錯誤輸出流 InputStream errorInput = p.getErrorStream();// 建立並實例化輸入字節流 BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorInput));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容 String eline = ""; while ((eline = errorReader.readLine()) != null) {// 循環讀取 System.out.println(eline);// 輸出 } errorReader.close();// 此處有依賴關係,先關閉errorReader errorInput.close();// 關閉流 } catch (IOException e) { output("執行" + cmd + "失敗!"); e.printStackTrace(); } int[] result = { cpu_result, vss, rss };// 新建數組保存數據 return result;// 返回數組 } /** * 獲取應用信息 利用Android系統dumpsys命令獲取 命令能統計到java虛擬的堆內存和棧內存的使用狀況 * * @return 返回內存佔用 */ public int getMemResult() { String cmd1 = Common.ADB_PATH + "adb shell dumpsys meminfo " + package_name; int mem_result = 0; try { Process p = Runtime.getRuntime().exec(cmd1);// 經過runtime類執行cmd命令 // 正確輸出流 InputStream input = p.getInputStream();// 建立並實例化輸入字節流 BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容 String line = ""; while ((line = reader.readLine()) != null) {// 循環讀取 if (line.startsWith(" TOTAL")) { mem_result = getMemInfo(line); } } reader.close();// 此處reader依賴於input,應先關閉 input.close(); // 錯誤輸出流 InputStream errorInput = p.getErrorStream();// 建立並實例化輸入字節流 BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorInput));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容 String eline = ""; while ((eline = errorReader.readLine()) != null) {// 循環讀取 System.out.println(eline);// 輸出 } errorReader.close();// 此處有依賴關係,先關閉errorReader errorInput.close(); } catch (IOException e) { output("執行" + cmd1 + "失敗!", e); } return mem_result; } /** * 獲取內存信息 * * @param info * 截取到的APP信息 * @return 返回內存蠶蛹 */ public int getMemInfo(String info) { int result = 0; Pattern r = Pattern.compile(" [0-9]+ "); Matcher m = r.matcher(info); if (m.find()) { // output(m.group()); result = changeStringToInt(m.group().trim()); } return result; } /** * 獲取cpu運行信息 * * @param info * 截取到的APP信息 * @return 返回CPU佔用率,採起double數據格式 */ public double getCpuInfo(String info) { String percent = info.substring(0, info.indexOf("%")); double result = changeStringToDouble(percent.trim()); return result; } /** * 獲取cpu運行信息 * * @param info * 截取到的APP信息 * @return 返回CPU佔用率,採起int數據格式 */ public int getCpuDate(String info) { Pattern pattern = Pattern.compile(" [0-9]*%"); Matcher matcher = pattern.matcher(info); matcher.find(); String date = matcher.group().trim(); return changeStringToInt(date.substring(0, date.length() - 1)); } public int getVss(String info) { Pattern pattern = Pattern.compile(" [0-9]+K"); Matcher matcher = pattern.matcher(info); matcher.find(); String date = matcher.group().trim(); return changeStringToInt(date.substring(0, date.length() - 1)); } public int getRss(String info) { Pattern pattern = Pattern.compile("K +[0-9]+K"); Matcher matcher = pattern.matcher(info); matcher.find(); String date = matcher.group().substring(1, matcher.group().length() - 1); return changeStringToInt(date.trim()); } // 把string類型轉化爲double public Double changeStringToDouble(String text) { // return Integer.parseInt(text); return Double.valueOf(text); } // 把string類型轉化爲int public int changeStringToInt(String text) { // return Integer.parseInt(text); return Integer.valueOf(text); } public void output(String text) {// 明顯輸出 System.out.println(text); } public void output(Object... object) { if (object.length == 1) { output(object[0].toString()); return; } for (int i = 0; i < object.length; i++) { System.out.println("第" + (i + 1) + "個:" + object[i]); } } }