1. Appium超時錯誤連接到驅動程序時問題,怎麼解決
問題
1. error: Failed to start an Appium session, err was: Error: Requested a new session but one was in progress
之前的會話沒有關閉,然後你又運行了測試實例,也沒有設置覆蓋.
解決:
1.重新停止appium服務,開啟Appium服務
2.在Genarel Setting那裡設置覆蓋Session,重啟Appium
測試結束在AfterClass加driver.quit()
2. error: Failed to start an Appium session, err was: Error: Command failed: C:Windowssystem32cmd.exe /s /c "D:android-sdk-windowsplatform-toolsadb.exe -s adb server version (32) doesn't match this client (36); killing…
wait-for-device"
error: could not installsmartsocketlistener: cannot bind to 127.0.0.1:5037:
沒有鏈接上手機或者模擬器,請確認已經連接成功,重新鏈接
3. error: Android devices must be of API level 17 or higher. Please change your device to Selendroid or upgrade Android on your device.
手機系統低於4.2,appium不支持4.2.2以下的系統,請換一個手機或者模擬器來測試。
4. Error: Permission to start activity denied.
**activity在清單文件裡面沒添加Android:exported="true"的話,你不能直接打開對應的activity,需要從啟動頁activity打開。
exported屬性就是設置是否允許activity被其它程序調用**
5. error: Failed to start an Appium session, err was: Error: Activity used to start app doesn't exist or cannot ve launched! Make usre it exists and is launchable activity
要打開的activity不存在,activity路徑錯誤,改為完整正確的activity路徑
6. error: Failed to start an Appium session, err was: Error: 'java - version' failed. Error: Command failed: C:Windowssystem32cmd.exe /s /c "java -version"
Java版本錯誤,請安裝最新的版本。
7.> info: [debug] Error: Command failed: C:Windowssystem32cmd.exe /s /c "D:android-sdk-windowsplatform-toolsadb.exe -s 8806a0b0 shell "echo 'ready'"error: unknown host service
鏈接手機失敗,重新鏈接手機即可,我就是重新拔插了一下usb
Error: Command failed: C:Windowssystem32cmd.exe /s /c "D:android-sdk-windowsplatform-toolsadb.exe -s 8806a0b0 shell "echo 'ping'""
error: unknown host service
adb被突然佔用導致,例如你在運行用例的時候運行了模擬器。
8. UIAutomatorViewer提示: Unable to connect to adb. Check if adb is installed correctly
解決,sdk升級到了25產生的問題。
解決方法:
將adb.exe復制一份到uiautomatorviewer.bat目錄下
修改uiautomatorviewer.bat文件最後一行(改binddir=%prog_dir%為自己的platform-tools本地路徑)
9 error: Failed to start an Appium session, err was:INSTALL_FAILED_ALREADY_EXISTS: Attempt to re-install io.appium.settings without first uninstalling
When you are at final step to execute test automation script for mobile app testing on a mobile emulator or a virtual device or a real device, you might observe that script execution fails with different kinds of errors, In context to current article you will look at the error and solutions for: INSTALL_FAILED_ALREADY_EXISTS: Attempt to re-install io.appium.settings without first uninstalling.
Error in Appium Server:
1
2
3
4
5
6
7
8
Error: Command failed: C:Windowssystem32cmd.exe /s /c
"C:Users{User}-toolsadb.exe -s
emulator-5554 install
"C:Program Files (x86)Appium ode_molesappiumuildsettings_apksettings_apk-debug.apk""
> Failed to install C:Program Files (x86)Appium ode_molesappiumuildsettings_apk
settings_apk-debug.apk: Failure [INSTALL_FAILED_ALREADY_EXISTS: Attempt to re-install
io.appium.settings without first uninstalling.]
Error in Android studio run console:
1
2
3
4
5
6
7
8
9
org.openqa.selenium.SessionNotCreatedException: A new session could not be created.
(Original error: Command failed: C:Windowssystem32cmd.exe /s /c
"C:Users{User}-toolsadb.exe -s emulator-5554 install
"C:Program Files (x86)Appium ode_molesappiumuildsettings_apksettings_apk-debug.apk""
Failed to install C:Program Files (x86)Appium ode_molesappiumuildsettings_apk
settings_apk-debug.apk: Failure [INSTALL_FAILED_ALREADY_EXISTS: Attempt to re-install
io.appium.settings without first uninstalling.]
) (WARNING: The server did not provide any stacktrace information)
Command ration or timeout: 0 milliseconds
For the first time when you execute the script itmight pass, but it will fail with above error when you try to execute the same or any other script multiple times. Or when your test script execution fails on the first attempt for some other reason, and when you fix it and execute it again, you might encounter this new issue.
原因:
The reason for this error is that Appium installs 2 mobile applications before executing the script.
1. io.appium.settings
2. io.appium.unlock
Theseare the supportive mobile applications appium utilizes to execute the test automation script in Mobile Emulator or virtual device or a real mobile device.
Ideally Appium should remove these files every time at the end of the script execution or termination, if it is intends to install themevery time a script is executed, or it should conditionally install these apps / apksto the mobile emulator or mobile device.
In your mobile emulator / Virtual Device / Real device, the 2 mobile applications appear as below:
There are multiple ways to troubleshootthis error and go ahead for asuccessful test script execution.
解決辦法
Solution 1: ADB's uninstall command to remove the files.
You can open command prompt, assuming that you already had set the environment variables for ANDROID_HOME and Path variables for sdk tools and platform tools.
And execute commands as shown below:
Solution 2: Uninstall manually
You can open the mobile emulator / virtual device / real device and go to apps and uninstall them.
Solution 3: Write code as part of your test automation script.
As part of your selenium test automation script, you could write instructions to execute the commands provided in solution 1 above, so that this issue would not arise.
Hope this article has been helpful and you are able to proceed further with script execution.
Request to kindly share any of your queries in form of comments, we would try our best to provide any solution for you.
10.出錯信息里含有"ps 'uiautomator',具體信息未 A new session could not be created. (Original error: Command failed: C:Windowssystem32cmd.exe /s /c "C:Userssxie-toolsadb.exe -s emulator-5554 shell "ps 'uiautomator'""
android-appium: A new session could not be created
junitexceptionandroidappium自動化
detail log:
org.openqa.selenium.SessionNotCreatedException: A new session could not be created. (Original error: Command failed: C:Windowssystem32cmd.exe /s /c "C:Userssxie-toolsadb.exe -s emulator-5554 shell "ps 'uiautomator'""
) (WARNING: The server did not provide any stacktrace information)
Command ration or timeout: 0 milliseconds
Build info: version: '3.4.0', revision: 'unknown', time: 'unknown'
System info: host: 'WL00070299', ip: '10.110.12.39', os.name: 'Windows 8.1', os.arch: 'x86', os.version: '6.3', java.version: '1.8.0_40'
Driver info: driver.version: AndroidDriver
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect..newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:215)
at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:167)
at io.appium.java_client.remote.AppiumProtocolHandShake.createSession(AppiumProtocolHandShake.java:161)
at io.appium.java_client.remote.AppiumProtocolHandShake.createSession(AppiumProtocolHandShake.java:76)
at io.appium.java_client.remote.AppiumCommandExecutor.doExecute(AppiumCommandExecutor.java:111)
at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:162)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:637)
at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:42)
at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:250)
at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:236)
at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:137)
at io.appium.java_client.DefaultGenericMobileDriver.(DefaultGenericMobileDriver.java:38)
at io.appium.java_client.AppiumDriver.(AppiumDriver.java:88)
at io.appium.java_client.AppiumDriver.(AppiumDriver.java:112)
at io.appium.java_client.android.AndroidDriver.(AndroidDriver.java:73)
at com.sky.demo.ContactTest.setUp(ContactTest.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schele(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
==========================================
直接在cmd中執行"C:Windowssystem32cmd.exe /s /c "C:Userssxie-toolsadb.exe -s emulator-5554 shell "ps 'uiautomator'""
bad pid 'uiautomator'", 報錯: bad pid 'uiautomator'
代碼內容為
public class ContactTest {
private AndroidDriver driver;
@Before
public void setUp() throws Exception {
//設置apk的路徑
File classpathRoot = new File(System.getProperty("user.dir"));
File appDir = new File(classpathRoot, "apps");
File app = new File(appDir, "ContactManager.apk");
}
解決辦法:
resolved by this way:
adb.js(C:Program Files (x86)Appium
ode_molesappium
ode_molesappium-adblibadb.js) 中1035 行this.shell("ps '" + name + "'", function (err, stdout) {
對應執行的指令是ps 'uiautomator', Android7不支持這個指令格式,所以執行結果是bad pid 'uiautomator'
目前Appium未對此進行處理,所以需要修改此指令的執行方式
即將
this.shell("ps '" + name + "'", function (err, stdout) {
if (err) return cb(err);
替換成
this.shell_grep("ps", name, function (err, stdout) {
if (err) {
logger.debug("No matching processes found");
return cb(null, []);
}
並增加上面用到的shell_grep函數:
ADB.prototype.shell_grep = function (cmd, grep, cb) {
if (cmd.indexOf('"') === -1) {
cmd = '"' + cmd + '"';
}
var execCmd = 'shell ' + cmd + '| grep ' + grep;
this.exec(execCmd, cb);
};
11.Android 7.0系統的手機無法執行appium腳本的問題
AppiumAppium 版本 1.4.16,Android 設備固件 7.x,執行腳本時,報錯使用語言:python報錯如下:
WebDriverException: Message: A new session could not be created. (Original error: Could not extract PIDs from ps output. PIDS: [], Procs: ["bad pid 'uiautomator'"])
這個是因為appium版本1.4.16使用的uiatumator1.0不支持的原因導致?如果不升級appium版本,是否有解決方案?
解決辦法
uiautomator1.0應該是不支持7.0,不升版本就換用uiautomator2.0吧,或者用下面的改腳本的方法使用。
解決Android 7.0系統的手機無法執行appium腳本的問題,改問題的具體解決方法如下:
找到appium的安裝目錄下的adb.js文件,windows版本的目錄如下:Appium
ode_molesappium
ode_molesappium-adblib
2、打開adb.js,手動修改該文件下的內容,此方法我已經試驗成功。
adb.js 中1035 行this.shell("ps '" + name + "'", function (err, stdout) {
對應執行的指令是ps 'uiautomator', Android7不支持這個指令格式,所以執行結果是bad pid 'uiautomator'
目前Appium未對此進行處理,所以需要修改此指令的執行方式
即將
this.shell("ps '" + name + "'", function (err, stdout) {
if (err) return cb(err);
替換成
this.shell_grep("ps", name, function (err, stdout) {
if (err) {
logger.debug("No matching processes found");
return cb(null, []);
}
並增加上面用到的shell_grep函數:
ADB.prototype.shell_grep = function (cmd, grep, cb) {
if (cmd.indexOf('"') === -1) {
cmd = '"' + cmd + '"';
}
var execCmd = 'shell ' + cmd + '| grep ' + grep;
this.exec(execCmd, cb);
};
網上還有如下的修改解決辦法:以下我未試驗。
ADB.prototype.getPIDsByName = function (name, cb) {
logger.debug("Getting all processes with '" + name + "'");
this.shell("ps '" + name + "'", function (err, stdout) {
if (err) return cb(err);
stdout = stdout.trim();
var procs = [];
var outlines = stdout.split("
");
outlines.shift(); //在該處添加此行代碼
3、重啟appium
技巧
1.每次測試都重新安裝app
為capabilities色設置noReset為true
capabilities.setCapability("noReset", true);
2.中文亂碼
這都是編碼問題:
1.方法1:
Android Studio修改文件編碼的方法,最底部的UTf-8,點擊選GBK就可以了,reload文件。(ps:先把文件內容全選復制一下再轉換編碼,再粘貼,不然文件內容就變亂碼了)
2.方法2:
用的是原來的UTF-8編碼,然後在測試mole的build.gradle裡面添加三行代碼
tasks.withType(JavaCompile){
options.encoding = 'UTF-8'
}
3.清除編輯框EditText內容
這個問題好像是看手機系統的,我之前的手機就會出現sendKeys的時候沒有全選去掉本來的內容,現在都會自動全選覆蓋了,這個也不算問題了。
/**
* 逐字刪除編輯框中的文字
* @param element 文本框架控制項
*/
public void clearText(AndroidElement element){
String className = element.getClass().getSimpleName();
if (className.equals("EditText")){
String text = element.getText();
//跳到最後
driver.pressKeyCode(KEYCODE_MOVE_END);
for (int i = 0; i < text.length(); i ++){
//循環後退刪除
driver.pressKeyCode(BACKSPACE);
}
}else {
print("不是文本輸入框架,無法刪除文字");
}
}
1
4.點擊輸入法鍵盤的回車搜索
方法1:切換輸入法
利用adb命令先切換為自己的輸入法,按了搜索再切換為appium的輸入法
查看當前手機的輸入法
cmd執行下面的的代碼
adb shell ime list -s
可以看到類似下面的結果,
C:UsersLITP>adb shell ime list -s
com..input_mi/.ImeService
com.sohu.inputmethod.sogou.xiaomi/.SogouIME
io.appium.android.ime/.UnicodeIME
C:UsersLITP>
執行adb命令
先寫好一個執行cmd的方法
/**
* 執行adb命令
* @param s 要執行的命令
*/
private void excuteAdbShell(String s) {
Runtime runtime=Runtime.getRuntime();
try{
runtime.exec(s);
}catch(Exception e){
print("執行命令:"+s+"出錯");
}
}
在需要搜索的時候執行下面的代碼,切換的輸入法用自己查看列表的輸入法內容,我這里是搜狗輸入法
//使用adb shell 切換輸入法-更改為搜狗拼音,這個看你本來用的什麼輸入法
excuteAdbShell("adb shell ime set com.sohu.inputmethod.sogou.xiaomi/.SogouIME");
//再次點擊輸入框,調取鍵盤,軟鍵盤被成功調出
clickView(page.getSearch());
//點擊右下角的搜索,即ENTER鍵
pressKeyCode(AndroidKeyCode.ENTER);
//再次切回 輸入法鍵盤為Appium unicodeKeyboard
excuteAdbShell("adb shell ime set io.appium.android.ime/.UnicodeIME");
2. Android性能測試(內存、cpu、fps、流量、GPU、電量)——adb篇
3)查看進程列表:adb shell "ps",同時也能獲取到應用的UID,方式如下(不需root許可權):
u0_a開頭的都是Android的應用進程,Android的應用的UID是從10000開始,到19999結束,可以在Process.java中查看到(FIRST_APPLICATION_UID和LAST_APPLICATION_UID),u0_a後面的數字就是該應用的UID值減去FIRST_APPLICATION_UID所得的值,所以,對於截圖這個應用進程,它是u0_a155,按前面的規制,它的UID就是155 + FIRST_APPLICATION_UID = 10155。
VSS - Virtual Set Size 虛擬耗用內存(包含共享庫佔用的內存)
RSS - Resident Set Size 實際使用物理內存(包含共享庫佔用的內存)
PSS - Proportional Set Size 實際使用的物理內存(比例分配共享庫佔用的內存)
USS - Unique Set Size 進程獨自佔用的物理內存(不包含共享庫佔用的內存)
一般來說內存佔用大小有如下規律:VSS >= RSS >= PSS >= USS
使用 adb shell "mpsys meminfo -s <pakagename | pid>"命令,輸出結果分以下4部分:
PS:在apk內調用運行獲取其他app的內存數據則需要root許可權
adb命令:adb shell mpsys gfxinfo <package | pid>
正常情況下幀率應該在16.67ms左右,1秒60幀,執行結果如下:
詳細計算方法如下:
還有一個命令是: adb shell mpsys SurfaceFlinger --latency LayerName
其中LayerName在各個不同系統中獲取的命令是不一樣的
在Android 6系統直接就是SurfaceView
在Android 7系統中可以通過 mpsys window windows | grep mSurface | grep SurfaceView 然後通過數據截取到
在Android 8系統中可以通過 mpsys SurfaceFlinger | grep android包名獲取到
執行命令結果如下:
計算方法比較簡單,一般列印出來的數據是129行(部分機型列印兩次257行,但是第一部分是無效數據,取後半部分),取len-2的第一列數據為end_time,取len-128的第一列數據為start_time
fps = 127/((end_time - start_time) / 1000000.0)
至於為啥要取第一列數據,這里不做過多介紹,歡迎參看這兩篇文章
老羅的文章SurfaceView原理
Android性能測試之fps獲取
至於為啥要處於1000000,因為命令列印出來的是納秒單位,要轉為毫秒進行計算,127就是因為命令一次列印出來127幀的數據而已
有兩種方法可以獲取
1) adb shell "top -n 5 | grep <package | pid>" ,第三列就是實時監控的CPU佔用率(-n 指定執行次數,不需root許可權),這邊top命令執行需要2到3s左右,一般可以採用busybox 的top命令執行,效率會快很多
2) adb shell "mpsys cpuinfo | grep <package | pid>"
兩種方法直接區別在於,top是持續監控狀態,而mpsys cpuinfo獲取的實時CPU佔用率數據
adb命令:adb shell "mpsys batterystats < package | pid>" (Android 5.0後引入)
獲取單個應用的耗電量信息,具體返回結果待研究
adb命令:adb shell "mpsys battery"
出現信息解讀:
AC powered:false 是否連接AC(電源)充電線
USB powered:true 是否連接USB(PC或筆記本USB插口)充電
Wireless powered:false 是否使用了無線電源
status: 1 電池狀態,2為充電狀態,其他為非充電狀態
level:58 電量(%)
scale: 100. 電量最大數值
voltage: 3977 當前電壓(mV)
current now: -335232. 當前電流(mA)
temperature:355 電池溫度,單位為0.1攝氏度
adb 命令:adb shell "mpsys< package | pid> | grep UID" [通過ps命令,獲取app的UID(安裝後唯一且固定)]
adb shell cat /proc/uid_stat/UID/tcp_rcv [cat為查看命令,讀取tcp_rcv獲取應用接收流量信息(設備重啟後清零)]
adb shell cat /proc/uid_stat/UID/tcp_snd [cat為查看命令,讀取tcp_snd獲取應用發送流量信息(設備重啟後清零)]
計算流量消耗步驟:
或者還有一種方式獲取應用流量消耗:
首先判斷類型:
cat /sys/class/thermal/thermal_zone*/type
只有紅框框出來的是有效的
cat /sys/class/thermal/thermal_zone*/temp
獲取CPU溫度
mpsys battery | grep temperature 單位0.1攝氏度
獲取/proc/stat文件內容(無許可權限制)
總的cpu時間片是 total = user+nice+system+idle+iowait+irq+softirq
忙碌時間為 notidle = user+nice+system +iowait+irq+softirq
cpu使用率計算方法為,先取開始的total值和忙碌時間notidle,隔一段時間片,再取一次計算total2,notidle2, cpuuse = (notidle2 – notidle) * 100 / (total2 - total)%
PS:由於Android 8許可權收緊,在Android 8系統手機內apk內讀取文件內容為空,需要shell許可權才可獲取文件內容,下同
讀/sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq文件的值,X不定,看是幾核手機,scaling_cur_freq是否存在也不一定,需要判斷
至於為啥不取cpuinfo_cur_freq文件的值,原因是android 6,7系統獲取的時候,這個文件shell沒有讀取許可權,需要root許可權
參考文章: https://blog.csdn.net/long_meng/article/details/45934899
Android 6,7系統可執行
mpsys window windows | grep "mCurrentFocus"
執行結果一般為類似:
mCurrentFocus=Window{81caaa5 u0 com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity}
按照一定規則把com.tencent.mobileqq提取出來即可
直接apk內讀取文件即可,不需要shell許可權(支持到Android8)
Gpu使用率獲取:會得到兩個值,(前一個/後一個)*100%=使用率
adb shell cat /sys/class/kgsl/kgsl-3d0/gpubusy
Gpu工作頻率:
adb shell cat /sys/class/kgsl/kgsl-3d0/gpuclk
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/cur_freq
Gpu最大、最小工作頻率:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/min_freq
Gpu可用頻率
adb shell cat /sys/class/kgsl/kgsl-3d0/gpu_available_frequencies
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/available_frequencies
Gpu可用工作模式:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/available_governors
Gpu當前工作模式:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/governor
3. 怎麼排查這些內存泄漏
最原始的內存泄露測試
重復多次操作關鍵的可疑的路徑,從內存監控工具中觀察內存曲線,是否存在不斷上升的趨勢且不會在程序返回時明顯回落。
這種方式可以發現最基本,也是最明顯的內存泄露問題,對用戶價值最大,操作難度小,性價比極高。
MAT內存分析工具
2.1 MAT分析heap的總內存佔用大小來初步判斷是否存在泄露
在Devices 中,點擊要監控的程序。
點擊Devices視圖界面中最上方一排圖標中的「Update Heap」
點擊Heap視圖
點擊Heap視圖中的「Cause GC」按鈕
到此為止需檢測的進程就可以被監視。Heap視圖中部有一個Type叫做data object,即數據對象,也就是我們的程序中大量存在的類類型的對象。在data object一行中有一列是「Total Size」,其值就是當前進程中所有Java數據對象的內存總量,一般情況下,這個值的大小決定了是否會有內存泄漏。可以這樣判斷:
進入某應用,不斷的操作該應用,同時注意觀察data object的Total Size值,正常情況下Total Size值都會穩定在一個有限的范圍內,也就是說由於程序中的的代碼良好,沒有造成對象不被垃圾回收的情況。
所以說雖然我們不斷的操作會不斷的生成很多對象,而在虛擬機不斷的進行GC的過程中,這些對象都被回收了,內存佔用量會會落到一個穩定的水平;反之如果代碼中存在沒有釋放對象引用的情況,則data object的Total Size值在每次GC後不會有明顯的回落。隨著操作次數的增多Total Size的值會越來越大,直到到達一個上限後導致進程被殺掉。
2.2 MAT分析hprof來定位內存泄露的原因所在。
這是出現內存泄露後使用MAT進行問題定位的有效手段。
A)Dump出內存泄露當時的內存鏡像hprof,分析懷疑泄露的類:
B)分析持有此類對象引用的外部對象
C)分析這些持有引用的對象的GC路徑
D)逐個分析每個對象的GC路徑是否正常
從這個路徑可以看出是一個antiRadiationUtil工具類對象持有了MainActivity的引用導致MainActivity無法釋放。此時就要進入代碼分析此時antiRadiationUtil的引用持有是否合理(如果antiRadiationUtil持有了MainActivity的context導致節目退出後MainActivity無法銷毀,那一般都屬於內存泄露了)。
2.3 MAT對比操作前後的hprof來定位內存泄露的根因所在。
為查找內存泄漏,通常需要兩個 Dump結果作對比,打開 Navigator History面板,將兩個表的 Histogram結果都添加到 Compare Basket中去
A) 第一個HPROF 文件(usingFile > Open Heap Dump ).
B)打開Histogram view.
C)在NavigationHistory view里 (如果看不到就從Window >show view>MAT- Navigation History ), 右擊histogram然後選擇Add to Compare Basket .
D)打開第二個HPROF 文件然後重做步驟2和3.
E)切換到Compare Basket view, 然後點擊Compare the Results (視圖右上角的紅色」!」圖標)。
F)分析對比結果
可以看出兩個hprof的數據對象對比結果。
通過這種方式可以快速定位到操作前後所持有的對象增量,從而進一步定位出當前操作導致內存泄露的具體原因是泄露了什麼數據對象。
注意:
如果是用 MAT Eclipse 插件獲取的 Dump文件,不需要經過轉換則可在MAT中打開,Adt會自動進行轉換。
而手機SDk Dump 出的文件要經過轉換才能被 MAT識別,Android SDK提供了這個工具 hprof-conv (位於 sdk/tools下)
首先,要通過控制台進入到你的 android sdk tools 目錄下執行以下命令:
./hprof-conv xxx-a.hprof xxx-b.hprof
例如 hprof-conv input.hprof out.hprof
此時才能將out.hprof放在eclipse的MAT中打開。
手機管家內存泄露每日監控方案
目前手機管家的內存泄露每日監控會自動運行並輸出是否存在疑似泄露的報告郵件,不論泄露對象的大小。這其中涉及的核心技術主要是AspectJ,MLD自研工具(原理是虛引用)和UIAutomator。
3.1 AspectJ插樁監控代碼
手機管家目前使用一個ant腳本加入MLD的監控代碼,並通過AspectJ的語法實現插樁。
使用AspectJ的原因是可以靈活分離出項目源碼與監控代碼,通過不同的編譯腳本打包出不同用途的安裝測試包:如果測試包是經過Aspect插樁了MLD監控代碼的話,那麼運行完畢後會輸出指定格式的日誌文件,作為後續分析工作的數據基礎。
3.2 MLD實現監控核心邏輯
這是手機管家內的一個工具工程,正式打包不會打入,BVT等每日監控測試包可以打入。打入後可以通過諸如addObject介面(通過反射去檢查是否含有該工具並調用)來加入需要監控的檢測對象,這個工具會自動在指定時機(如退出管家)去檢測該對象是否發生泄漏。
這個內存泄露檢測的基本原理是:
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用必須和引用隊列(ReferenceQueue)聯合使用(在虛引用函數就必須關聯指定)。當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,自動把這個虛引用加入到與之關聯的引用隊列中。程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。
基於以上原理,MLD工具在調用介面addObject加入監控類型時,會為該類型對象增加一個虛引用,注意虛引用並不會影響該對象被正常回收。因此可以在ReferenceQueue引用隊列中統計未被回收的監控對象是否超過指定閥值。
利用PhantomReferences(虛引用)和ReferenceQueue(引用隊列),當PhantomReferences被加入到相關聯的ReferenceQueue時,則視該對象已經或處於垃圾回收器回收階段了。
MLD監控原理核心
目前手機管家已對大部分類完成內存泄露的監控,包括各種activity,service和view頁面等,務求在技術上能帶給用戶最順滑的產品體驗。
接下來簡單介紹下這個工具的判斷核心。根據虛引用監控到的內存狀態,需要通過多種策略來判斷是否存在內存泄露。
(1)最簡單的方式就是直接在加入監控時就為該類型設定最大存在個數,舉個例子,各個DAO對象理論上只能存在最多一個,因此一旦出現兩個相同的DAO,那一般都是泄露了;
(2)第二種情況是在頁面退出程序退出時,檢索gc後無法釋放的對象列表,這些對象類型也會成為內存泄露的懷疑對象;
(3)最後一種情況比較復雜,基本原理是根據歷史操作判斷對象數量的增長幅度。根據對象的增長通過最小二乘法擬合出該對象類型的增長速度,如果超過經驗值則會列入疑似泄露的對象列表。
3.3 UIAutomator完成重復操作的自動化
最後一步就很簡單了。這么多反復的UI操作,讓人工來點就太浪費人力了。我們使用UIAutomator來進行自動化操作測試。
目前手機管家的每日自動化測試已覆蓋各個功能的主路徑,並通過配置文件的方式來靈活驅動用例的增刪改查,最大限度保證了隨著版本推移用例的復用價值。
至此手機管家的內存泄露測試方案介紹完畢,也歡迎各路牛人交流溝通更多更強的內存泄露工具盒方案!
騰訊Bugly簡介
Bugly是騰訊內部產品質量監控平台的外發版本,其主要功能是App發布以後,對用戶側發生的Crash以及卡頓現象進行監控並上報,讓開發同學可以第一時間了解到App的質量情況,及時機型修改。目前騰訊內部所有的產品,均在使用其進行線上產品的崩潰監控。
4. 我手機進入了apply update from ADB 這是什麼
apply update from ADB 從ADB進行更新。 ADB: ADB驅動是Android設備(如手機)連接PC時仿陵基所需要的應用程序。請試試以下方法:
直接長按電源鍵關機重啟,等了兩三分鍾自備謹動回到汪螞重啟位置,按重啟一切正常。
如果是三星手機,只有拆電池再進入 Odin3 線刷模式,再使用完美刷機助手。