當前位置:首頁 » 安卓系統 » android靜態分析

android靜態分析

發布時間: 2022-11-27 02:56:16

『壹』 手機調試Android程序出異常時不列印堆棧信息

列印堆棧是調試的常用方法,一般在系統異常時,我們可以將異常情況下的堆棧列印出來,這樣十分方便錯誤查找。實際上還有另外一個非常有用的功能:分析代碼的行為。android代碼太過龐大復雜了,完全的靜態分析經常是無從下手,因此通過列印堆棧的動態分析也十分必要。

Android列印堆棧的方法,簡單歸類一下
1. zygote的堆棧mp
實際上這個可以同時mp java線程及native線程的堆棧,對於java線程,java堆棧和native堆棧都可以得到。
使用方法很簡單,直接在adb shell或串口中輸入:
[plain] view plain
kill -3 <pid>
輸出的trace會保存在 /data/anr/traces.txt文件中。這個需要注意,如果沒有 /data/anr/這個目錄或/data/anr/traces.txt這個文件,需要手工創建一下,並設置好讀寫許可權。
如果需要在代碼中,更容易控制堆棧的輸出時機,可以用以下命令獲取zygote的core mp:
[java] view plain
Process.sendSignal(pid, Process.SIGNAL_QUIT);
原理和命令行是一樣的。
不過需要注意兩點:
adb shell可能會沒有許可權,需要root。
android 4.2中關閉了native thread的堆棧列印,詳見 dalvik/vm/Thread.cpp的mpNativeThread方法:
[cpp] view plain
dvmPrintDebugMessage(target,
"\"%s\" sysTid=%d nice=%d sched=%d/%d cgrp=%s\n",
name, tid, getpriority(PRIO_PROCESS, tid),
schedStats.policy, schedStats.priority, schedStats.group);
mpSchedStat(target, tid);
// Temporarily disabled collecting native stacks from non-Dalvik
// threads because sometimes they misbehave.
//dvmDumpNativeStack(target, tid);
Native堆棧的列印被關掉了!不過對於大多數情況,可以直接將這個注釋打開。

2. debuggerd的堆棧mp
debuggerd是android的一個daemon進程,負責在進程異常出錯時,將進程的運行時信息mp出來供分析。debuggerd生 成的coremp數據是以文本形式呈現,被保存在 /data/tombstone/ 目錄下(名字取的也很形象,tombstone是墓碑的意思),共可保存10個文件,當超過10個時,會覆蓋重寫最早生成的文件。從4.2版本開 始,debuggerd同時也是一個實用工具:可以在不中斷進程執行的情況下列印當前進程的native堆棧。使用方法是:
[plain] view plain
debuggerd -b <pid>
這可以協助我們分析進程執行行為,但最最有用的地方是:它可以非常簡單的定位到native進程中鎖死或錯誤邏輯引起的死循環的代碼位置。

3. java代碼中列印堆棧
Java代碼列印堆棧比較簡單, 堆棧信息獲取和輸出,都可以通過Throwable類的方法實現。目前通用的做法是在java進程出現需要注意的異常時,列印堆棧,然後再決定退出或挽救。通常的方法是使用exception的printStackTrace()方法:
[java] view plain
try {
...
} catch (RemoteException e) {
e.printStackTrace();
...
}
當然也可以只列印堆棧不退出,這樣就比較方便分析代碼的動態運行情況。Java代碼中插入堆棧列印的方法如下:
[java] view plain
Log.d(TAG,Log.getStackTraceString(new Throwable()));

4. C++代碼中列印堆棧
C++也是支持異常處理的,異常處理庫中,已經包含了獲取backtrace的介面,Android也是利用這個介面來列印堆棧信息的。在Android的C++中,已經集成了一個工具類CallStack,在libutils.so中。使用方法:
[cpp] view plain
#include <utils/CallStack.h>
...
CallStack stack;
stack.update();
stack.mp();
使用方式比較簡單。目前Andoid4.2版本已經將相關信息解析的很到位,符號表查找,demangle,偏移位置校正都做好了。
[plain] view plain

5. C代碼中列印堆棧
C代碼,尤其是底層C庫,想要看到調用的堆棧信息,還是比較麻煩的。 CallStack肯定是不能用,一是因為其實C++寫的,需要重新封裝才能在C中使用,二是底層庫反調上層庫的函數,會造成鏈接器循環依賴而無法鏈接。 不過也不是沒有辦法,可以通過android工具類CallStack實現中使用的unwind調用及符號解析函數來處理。
這里需要注意的是,為解決鏈接問題,最好使用dlopen方式,查找需要用到的介面再直接調用,這樣會比較簡單。如下為相關的實現代碼,只需要在要 列印的文件中插入此部分代碼,然後調用getCallStack()即可,無需包含太多的頭文件和修改Android.mk文件:
[cpp] view plain
#define MAX_DEPTH 31
#define MAX_BACKTRACE_LINE_LENGTH 800
#define PATH "/system/lib/libcorkscrew.so"

typedef ssize_t (*unwindFn)(backtrace_frame_t*, size_t, size_t);
typedef void (*unwindSymbFn)(const backtrace_frame_t*, size_t, backtrace_symbol_t*);
typedef void (*unwindSymbFreeFn)(backtrace_symbol_t*, size_t);

static void *gHandle = NULL;

static int getCallStack(void){
ssize_t i = 0;
ssize_t result = 0;
ssize_t count;
backtrace_frame_t mStack[MAX_DEPTH];
backtrace_symbol_t symbols[MAX_DEPTH];

unwindFn unwind_backtrace = NULL;
unwindSymbFn get_backtrace_symbols = NULL;
unwindSymbFreeFn free_backtrace_symbols = NULL;

// open the so.
if(gHandle == NULL) gHandle = dlopen(PATH, RTLD_NOW);

// get the interface for unwind and symbol analyse
if(gHandle != NULL) unwind_backtrace = (unwindFn)dlsym(gHandle, "unwind_backtrace");
if(gHandle != NULL) get_backtrace_symbols = (unwindSymbFn)dlsym(gHandle, "get_backtrace_symbols");
if(gHandle != NULL) free_backtrace_symbols = (unwindSymbFreeFn)dlsym(gHandle, "free_backtrace_symbols");

if(!gHandle ||!unwind_backtrace ||!get_backtrace_symbols || !free_backtrace_symbols ){
ALOGE("Error! cannot get unwind info: handle:%p %p %p %p",
gHandle, unwind_backtrace, get_backtrace_symbols, free_backtrace_symbols );
return result;
}

count= unwind_backtrace(mStack, 1, MAX_DEPTH);
get_backtrace_symbols(mStack, count, symbols);

for (i = 0; i < count; i++) {
char line[MAX_BACKTRACE_LINE_LENGTH];

const char* mapName = symbols[i].map_name ? symbols[i].map_name : "<unknown>";
const char* symbolName =symbols[i].demangled_name ? symbols[i].demangled_name : symbols[i].symbol_name;
size_t fieldWidth = (MAX_BACKTRACE_LINE_LENGTH - 80) / 2;

if (symbolName) {
uint32_t pc_offset = symbols[i].relative_pc - symbols[i].relative_symbol_addr;
if (pc_offset) {
snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s+%u)",
i, symbols[i].relative_pc, fieldWidth, mapName,
fieldWidth, symbolName, pc_offset);
} else {
snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s)",
i, symbols[i].relative_pc, fieldWidth, mapName,
fieldWidth, symbolName);
}
} else {
snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s",
i, symbols[i].relative_pc, fieldWidth, mapName);
}

ALOGD("%s", line);
}

free_backtrace_symbols(symbols, count);

return result;
}
對sched_policy.c的堆棧調用分析如下,注意具體是否要列印,在哪裡列印,還可以通過pid、uid、property等來控制一下,這樣就不會被淹死在trace的汪洋大海中。
[plain] view plain
D/SchedPolicy( 1350): #00 pc 0000676c /system/lib/libcutils.so
D/SchedPolicy( 1350): #01 pc 00006b3a /system/lib/libcutils.so (set_sched_policy+49)
D/SchedPolicy( 1350): #02 pc 00010e82 /system/lib/libutils.so (androidSetThreadPriority+61)
D/SchedPolicy( 1350): #03 pc 00068104 /system/lib/libandroid_runtime.so (android_os_Process_setThreadPriority(_JNIEnv*, _jobject*, int, int)+7)
D/SchedPolicy( 1350): #04 pc 0001e510 /system/lib/libdvm.so (dvmPlatformInvoke+112)
D/SchedPolicy( 1350): #05 pc 0004d6aa /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+417)
D/SchedPolicy( 1350): #06 pc 00027920 /system/lib/libdvm.so
D/SchedPolicy( 1350): #07 pc 0002b7fc /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
D/SchedPolicy( 1350): #08 pc 00060c30 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+271)
D/SchedPolicy( 1350): #09 pc 0004cd34 /system/lib/libdvm.so
D/SchedPolicy( 1350): #10 pc 00049382 /system/lib/libandroid_runtime.so
D/SchedPolicy( 1350): #11 pc 00065e52 /system/lib/libandroid_runtime.so
D/SchedPolicy( 1350): #12 pc 0001435e /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+57)
D/SchedPolicy( 1350): #13 pc 00016f5a /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+513)
D/SchedPolicy( 1350): #14 pc 00017380 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+183)
D/SchedPolicy( 1350): #15 pc 0001b160 /system/lib/libbinder.so
D/SchedPolicy( 1350): #16 pc 00011264 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)
D/SchedPolicy( 1350): #17 pc 000469bc /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+63)
D/SchedPolicy( 1350): #18 pc 00010dca /system/lib/libutils.so
D/SchedPolicy( 1350): #19 pc 0000e3d8 /system/lib/libc.so (__thread_entry+72)
D/SchedPolicy( 1350): #20 pc 0000dac4 /system/lib/libc.so (pthread_create+160)
D/SchedPolicy( 1350): #00 pc 0000676c /system/lib/libcutils.so
D/SchedPolicy( 1350): #01 pc 00006b3a /system/lib/libcutils.so (set_sched_policy+49)
D/SchedPolicy( 1350): #02 pc 00016f26 /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+461)
D/SchedPolicy( 1350): #03 pc 00017380 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+183)
D/SchedPolicy( 1350): #04 pc 0001b160 /system/lib/libbinder.so
D/SchedPolicy( 1350): #05 pc 00011264 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)
D/SchedPolicy( 1350): #06 pc 000469bc /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+63)
D/SchedPolicy( 1350): #07 pc 00010dca /system/lib/libutils.so
D/SchedPolicy( 1350): #08 pc 0000e3d8 /system/lib/libc.so (__thread_entry+72)
D/SchedPolicy( 1350): #09 pc 0000dac4 /system/lib/libc.so (pthread_create+160)

6. 其它堆棧信息查詢

『貳』 電腦 文件 androidstudio1.3有什麼用

1.項目設置在開始暢游AndroidStudio的世界之前,大家首先需要點擊此處下載並進行安裝。請注意,各位必須事先安裝好JDK6或者更高版本。如果是在Windows系統環境下,先啟動.exe文件、而後按照安裝向導的指示一步步完成。如果大家使用的是OSX系統,則首先雙擊啟動磁碟鏡像,然後將AndroidStudio拖拽到自己的應用程序文件夾當中。在成功完成了以上各項步驟後,那麼大家的開發環境應該已經得到了正確設置。接下來,我們可以准備好利用AndroidStudio創建自己的第一款Android應用程序了。當大家第一次啟動AndroidStudio時,應該會看到該軟體的歡迎屏幕,其中還提供一些選項、指導我們以此為起點邁出Android應用開發的第一步。在今天的教程中,我們將選擇「NewProject(新項目)」選項。不過如果大家希望把Eclipse等其它環境中的現有項目轉化為AndroidStudio項目,也可以選擇「ImportProject(導入項目)」。AndroidStudio能夠將Eclipse項目轉換為AndroidStudio項目,並在項目中為用戶提供必要的配置文件。如果大家在選項列表中點擊了「OpenProject(打開項目)」,則可以開啟已經利用AndroidStudio或者IntelliJIDEA創建出的項目。而選擇「CheckoutfromVersionControl(版本控制檢查)」的話,大家能夠對處於版本控制之下的項目副本進行檢查。通過這種方式,我們可以將現有項目作為基礎、快速構建起新的針對性版本。由於我們需要從零開始,因此這里選擇「新項目」。這時大家會看到一份選項列表,旨在對我們的新項目作出配置。在今天的教程中,我們將創建一款簡單的應用程序,主要目的是為大家演示AndroidStudio中最為重要的一部分功能特性。相信大家也和我一樣,會認為「HelloWorld」這個名稱最適合本次開發出的新項目。正如大家在上面這幅截圖中所看到,我把自己的應用程序命名為HelloWorld,並為其設定了模塊名稱。如果大家對IntelliJIDEA不太熟悉,可能不知道模塊這東西到底是什麼。模塊實際上就是一個可以進行編譯、運行、測試以及調試的獨立功能單元。模塊當中包含有源代碼、編譯腳本以及用於特定任務的其它組成部分。在創建新項目時,大家還可以為該項目設定軟體包名稱。在默認情況下,AndroidStudio會將項目包名稱的最後一項元素設置為模塊名稱,但只要願意、大家可以隨意對其作出變更。其它設定內容還包括項目在設備上的保存位置、最低與推薦SDK、項目編譯需要使用的SDK以及項目主題等等。大家也可以要求AndroidStudio創建一個Activity類、為其自定義一個啟動圖標,或者設定該項目是否支持GridLayout、Fragments、NavigationDrawer或者ActionBar等。這里我們不會為自己的應用程序創建自定義圖標,因此大家可以取消「Createcustomlaunchicon(創建自定義啟動圖標)」項目前的勾選框。點擊「Next(下一步)」繼續進行其它項目設置步驟。由於我們在之前的步驟中勾選了「Createactivity(創建activity)」項目的勾選框,因此這里導航會要求大家對AndroidStudio將為我們創建的Activity類進行配置。由於我們將從空白Activity類開始進行配置,因此大家可以點擊「Next」執行設置流程的下面幾個步驟。這里大家需要對該Activity類、主布局以及片段布局進行命名。大家也可以設置導航類型,在今天的示例項目中我們將其設置為「None」。下面這幅截圖顯示的是我們的設置方案看起來是什麼樣子。在點擊「Finish」之後,大家會看到如下圖所示的AndroidStudio用戶界面。其中窗口左側為項目資源管理器,右側則為工作區。在AndroidStudio中對項目進行設置之後,現在我們可以逐一查看AndroidStudio當中的各項關鍵功能。2.Android虛擬設備所謂Android虛擬設備——或者簡稱AVD——是一套模擬器配置方案,它允許大家設定出與實際情況相符的Android設備型號。這就讓開發者在多種多樣的設備平台上運行並測試應用程序變得更為輕松。在Android虛擬設備功能的支持下,大家可以為Android模擬器指定需要模擬的硬體與軟體組合。創建Android虛擬設備的首選方式是通過AVDManager。大家可以在AndroidStudio用戶界面的Tools菜單中依次選擇Android〉AVDManager。如果大家之前對開發環境的設置工作正確無誤,那麼Android虛擬設備管理器的界面應該如下圖所示。要創建新的AVD,我們需要點擊右側的「New…」、為AVD設定名稱並如下圖所示對虛擬設備進行配置。最後點擊「OK」以創建自己的第一套AVD。要使用我們剛剛創建好的AVD,首先需要在AVD管理器的列表中將其選中,然後點擊窗口右側的「Start…」。如果大家的AVD設置過程正確無誤,那麼Android模擬器在啟動後應該如下圖所示。既然Android模擬器已經成功啟動並開始運行,現在是時候啟動我們的應用程序了。在「Run」菜單中選擇「Run『helloworld』」——沒錯,在Android模擬器中運行應用程序就是這么簡單。3.實時布局(LiveLayout)AndroidStudio中的實時布局功能允許大家在無需將應用程序運行在設備或者模擬器中的前提下,直接預覽應用的用戶界面。實時布局是一款極為強大的工具,能夠幫助開發者節約大量時間。在實時布局的幫助下,查看應用程序用戶界面的任務變得輕松而且快捷。要使用實時布局,我們需要雙擊對應XML布局文件並選擇工作區下方的「Text」標簽。接下來選擇工作區右側的「Preview」標簽來預覽當前布局。我們對XML布局作出的任何變更都會直接反映在右側的預覽窗口當中。大家可以查看下面這幅截圖來深入理解這項功能。實時布局功能為我們帶來了諸多值得稱道的顯著優勢。舉例來說,大家可以在Preview面板的第一項菜單中選擇選項,從而對當前正在使用的XML布局隨意作出調整。譬如說,大家可以分別創建不同的縱向與橫向顯示視圖,AndroidStudio會承擔起創建必要文件夾及文件的任務。Preview面板中的第二項菜單允許大家變更顯示在Preview面板內的設備大小。第三項菜單的作用則是調整設備在Preview面板中的朝向,這樣我們就能更輕松地查看同一套布局方案在不同顯示模式(縱向與橫向)下的效果與主題。Preview面板中的第四項菜單允許我們輕松訪問Activity或者布局所使用的個別片段。Preview面板還允許大家變更在實時布局中使用的語言,從而輕松預覽不同語言在布局方案中的顯示效果。最右邊的菜單的作用則是調整API版本。Preview面板中還包含多項控制機制,例如對布局進行縮放、重新Preview面板或者截取當前屏幕。4.模板AndroidStudio還為開發人員提供多種模板選項,從而大大提升開發速度。這些模板能自動創建Activity以及必要的XML文件。大家還可以利用這些模板創建出較為基礎的Android應用程序,並將其運行在實體設備或者模擬器當中。在AndroidStudio當中,我們可以在創建新的Activity時一同創建出對應模板。右鍵點擊窗口左側項目瀏覽器中的「packagename」並在菜單中選擇「New」,而後從選項列表中點選「Activity」。AndroidStudio隨後會為開發者列出模板清單,其中包括BlankActivity、FullscreenActivity以及TabbedActivity。大家還可以從菜單中選擇「ImageAsset」,接下來的向導會指引我們一步步完成創建流程。下面讓我們一起來看看如何以LoginActivity模板為基礎創建一套新的Activity。首先在Acivity模板列表中選擇LoginActivity選項以啟動創建向導。如大家在上面的截圖中所見,我已經將新建的Activity命名為LoginActivity——也就是為activitylogin設定LayoutName——並為該Activity添加了一個名為SignIn的標題。在默認情況下,對話框中的IncludeGoogle+signin項目已經被勾選。由於我們不打算在今天的示例中使用Google+登錄功能,因此取消該勾選項。大家可以選擇為這套新的Activity設定HierarchicalParent(分層結構)。這樣當我們點擊設備上的後退按鈕時,應用就將通過導航返回至上一界面。我們將這一欄位留空。在點擊「Finish」之後,AndroidStudio會為我們創建出必要的文件及文件夾。如果一切進展順利,我們將在項目當中看到新的Activity與Layout。下一布工作是在manifest文件中對新Activity進行設置,這樣它就能在應用程序啟動時作為主Activity加以使用了。請大家一起來看下面的manifest文件內容,其中LoginActivity類擁有自己的活動節點。為了在應用程序當中啟動我們剛剛創建的LoginActivity,首先需要移除原有LoginActivity類的活動節點,然後利用com.tuts.HelloWorld.LoginActivity代替先前的com.tuts.HelloWorld.MainActivity。這樣一來,應用程序現在就將使用LoginActivity類作為其主Activity。當我們在模擬器當中創建並運行自己的應用程序時,首先應該會看到如下圖所示的顯示內容。這意味著我們已經成功利用剛剛創建的LoginActivity類取代了原有的空白Activity類。5.Lint工具對代碼進行測試是一回事,但同樣重要的是、我們還需要在編寫代碼的同時引入各種最佳實踐。這不僅能夠顯著改進性能表現,也能增加應用程序的整體穩定性。另外,經過合理結構調整的項目在維護方面也更為輕松。AndroidStudio中提供的AndroidLint是一款靜態分析工具,它負責對項目源代碼加以分析。它能夠檢測出應用程序中的潛在漏洞以及其它可能被編譯器所忽略的其它代碼問題。就以下面這幅截圖為例,大家可以看到該布局中的LinearLayout並未得到實際使用。AndroidLint的優勢在於,它能幫助我們重視警告或報錯信息的出現原因,從而更輕松地修復或者解決這些問題。請大家養成重復使用AndroidStudioLint工具的好習慣,這能幫助我們准確檢測到項目當中存在的潛在問題。Lint工具甚至能告訴我們應用程序中是否存在重復的圖片或者編譯內容。要運行Lint工具,大家首先需要在AndroidStudio的「Analyze」菜單中選擇「InspectCode…」。當AndroidStudio完成了對項目的檢測之後,它會在窗口底部顯示出分析結果。請注意,除了AndroidLint之外,AndroidStudio還提供一系列其它檢查功能。只需雙擊某個已經發現的問題,系統就會幫助大家定位到對應文件中存在問題的位置。6.富布局編輯器AndroidStudio提供一套富布局編輯器,大家可以在其中隨意拖拽各類用戶界面組件。大家還可以在多屏幕配置中同時查看多種布局的顯示效果,這一點我們在前文中已經提到過。這款富布局編輯器在使用方面非常直觀簡單。我們首先需要一套要處理的布局方案。瀏覽到項目中res文件夾下的layout文件夾,右鍵點擊layout文件夾,然後在彈出的菜單中選擇New>Layoutresourcefile。下面為新布局設定一個名稱與root元素,而後點擊「OK」。AndroidStudio會自動在窗口右側的編輯器當中打開該布局。在編輯器的底部,大家會看到兩個標簽,分別是Design與Text。點擊Text標簽後編輯器將被激活,這樣我們就能對當前選定的布局方案作出變更。點擊Design標簽則會激活另一套編輯器內容,其中顯示出布局的預覽效果。要向布局當中添加其它功能性組件,我們只需將其從布局左側的組件列表中拖出並放入布局內即可。是的,就這么簡單。

『叄』 如何分析android的OOM,與java靜態代碼分析工具

1.用MAT分析OOM
很多OOM看似發生在bitmap 分配得時候,但它一般不是rootcause。根本原因都在於本應該自動釋放的資源,因為代碼的錯誤,而導致某些對象一直被引用(Reference)。
2.java靜態代碼分析工具
寫代碼過程中難免會有疏漏,我們也可以藉助工具分析,這里是常用的java靜態代碼分析工具:
http://www.oschina.net/question/129540_23043
個人覺得Find Bugs 和 PMD就可以了,只是輔助,不必過分依賴,他並不是萬能的,不是所有錯誤都能找出來。

『肆』 android studio 怎麼用findbugs

在Android開發中,會出現一些比較不容易發現的bug,比如對於null的判斷,出現遺漏的時候會出現'NullPointException',比如下面的代碼:
if (ta != null) {
mPanelHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoPanelHeight, -1);
mShadowHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoShadowHeight, -1);
mParallaxOffset = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_umanoParalaxOffset, -1);

.......
}

ta.recycle();

開頭的時候判斷ta不為null的情況,但是在調用 ta.recycle() 的時候是在if之外,但調用這個方法的時候,傳入的參數ta為null的時候就會出現 NullPointException ,如果能夠通過工具找到這種潛在的bug就最好不過了。
FindBugs
FindBugs 是一個Java靜態分析工具,用來檢查類或者jar文件,用來發現可能的問題。檢測完成之後會生成一份詳細的報告,藉助這份報告可以找到潛在的bug,比如 NullPointException ,特定的資源沒有關閉,查詢資料庫沒有調用 Cursor.close() 等,如果才用人工的方式很難才能發現類似的bug,或者這些bug永遠不會發現,直到運行時才發現,還有可能是一直沒有出現,別人調用的時候沒有做檢查就調用了.....
Java的靜態分析工具當然可以無難度的在Android上面運行,通過這種FindBugs的檢查可以讓App的運行更加的穩定。
FindBugs官網地址: http://findbugs.sourceforge.net/
Gradle的FindBugs插件
FindBugs在Gradle中是當做一個插件存在的,可以在Android Studio中直接使用:
apply plugin: "findbugs"

task findbugs(type: FindBugs,dependsOn:'assembleDebug') {

ignoreFailures= true
effort= "default"
reportLevel= "high"
println( "$project.buildDir")
classes = files("$project.buildDir/intermediates/classes")
source= fileTree("src/main/java/")
classpath= files()
reports{
xml.enabled=false
html.enabled=true
xml {
destination "$project.buildDir/findbugs.xml"
}
html{
destination "$project.buildDir/findbugs.html"
}
}
}

首先引入 FindBugs 的插件。
定義一個 task 任務,這個任務的類型是 FindBugs ,依賴 assembleDebug 母的是先生成.classe文件。
ignoreFailures :有警告錯誤的時候也是允許構建。
reportLevel :報告的級別, Low , Medium , High 一般來說我們首先關注的是高級別的報告,再關注低一級別的報告。
classes 和 source 分別是對應的.classe文件夾地址,和源代碼文件地址。
repoets 指定報告類型,有兩種方式 xml 和 html ,只允許一種輸出格式。
在右側的Gradle的對於的Mole可以在Tasks中找到對應的findBugs任務,點擊即可運行。
報告
我們會得到對應的一個類似與這樣的報告:
問題發現的例子:
1.NP:`Possible null pointer dereference `,可能出現null的代碼。
2.HE:重寫對戲那個的equals()方法,但是沒有重寫它的hashCode方法。或者相反。
3.SE:serializable錯誤

更多的內容解讀可以點擊詳情,可以看到錯誤對應的代碼行號,和錯誤詳情,以及相關檢測錯誤的解釋。
運行時機
什麼時候運行是一個問題,一般情況下在原有的項目中加入findBugs之後,會檢測出以前的代碼存在的一些問題,所以在使用findBugs的時候應該做一次全面的檢查,解決到對於的問題。
其他運行的時機,我覺得是,在完成一個版本對應功能的時候要運行檢查一次,防止寫的代碼有潛在的bug,另一個時間點就是在每次修復完Bug之後,在運行一次,防止修復Bug的時候,引入新的Bug。

『伍』 如何提高 Android 代碼質量

(1)插件安裝
在Android Studio中選擇Preferences -> Plugins,輸入查找findBugs進行插件安裝。
(2)插件使用
在build.gradle文件中,按照下面步驟進行設置:
添加plugin apply plugin:』findbugs』
定義任務,指定輸出格式
這里要注意因為findBugs是檢查class文件,所以在定義task的時候,是dependsOn: 「assembleDebug」,確保運行findbugs的task能夠成功檢測。
通過gradle findbugs方式,在工程目錄下運行命令,檢測完成後,會在制定的目錄下生成報告文檔。文檔支持xml和html兩種格式,本文設置的是html格式,可以直接用瀏覽器打開。
當然,和lint一樣,findBugs也支持手動檢測的方式。
在工程里,右鍵 FindBugs -> (選擇檢測的范圍)。檢測完之後,底部工具欄會跳到FindBugs-IEDA下。
3
PMD

PMD是一個很有用的工具,它跟Findbugs類似,但是它不是檢測位元組碼,它是直接檢測源代碼。它使用靜態分析來發現錯誤。

為什麼要將它們同時使用呢?因為它們的檢測方法不同,可以取到互補的作用。

檢測范圍
可能的bug——空的try/catch/finally/switch塊。
無用代碼(Dead code):無用的本地變數,方法參數和私有方法。
空的if/while語句。
過度復雜的表達式——不必要的if語句,本來可以用while循環但是卻用了for循環。
可優化的代碼:浪費性能的String/StringBuffer的使用。

(1)插件安裝

同樣可以通過AS的plugin進行安裝,推薦安裝QAPlug-PMD。

(2)插件使用

在build.gradle文件中進行如下配置

導入Plugin:apply plugin: 『pmd』
Task配置

4
CheckStyles

這個工具用來自動檢測java源碼。啟動之後,可以按照制定的規則對java源碼進行檢查,被將所有的不符合規范的地方生成報告通知給你。

檢測范圍
註解
javadoc注釋
命名規范
文件頭
導入包規范
尺寸設置
空格
正則表達式
修飾符
代碼塊
編碼問題
類設計問題
重復、度量以及一些雜項

總而言之,是一些代碼規范問題!!

(1)插件安裝

通過AS的Plugin進行安裝

(2)插件使用

導入Plugin
apply plugin: 『checkstyle』
設置CheckStyle的版本
checkstyle {
toolVersion 『6.1.1』
showViolations true
}
配置任務

5
插件的接入與使用

檢測范圍
lint、PMD、findBugs和CheckStyle檢測范圍之和。

(1)插件安裝

下載整合插件的文件包(文末),和app工程目錄同級放置。
在app的build.gradle文件導入整合插件腳本
apply from: 『../config/quality.gradle』

(2)插件使用

修改quality.gradle 的appDir欄位,設置檢測的工程目錄
// 應用目錄名稱def appDir = 「app-k12」
進入工程根目錄,運行gradle check,檢測完成後,會在build/reports下生成相應的檢測報告文件。當然也可以按照每個插件的使用方式單獨使用。

『陸』 Android Studio怎麼用

1.項目設置
在開始暢游Android Studio的世界之前,大家首先需要點擊此處下載並進行安裝。請注意,各位必須事先安裝好JDK 6或者更高版本。如果是在Windows系統環境下,先啟動.exe文件、而後按照安裝向導的指示一步步完成。如果大家使用的是OS X系統,則首先雙擊啟動磁碟鏡像,然後將Android Studio拖拽到自己的應用程序文件夾當中。
在成功完成了以上各項步驟後,那麼大家的開發環境應該已經得到了正確設置。接下來,我們可以准備好利用Android Studio創建自己的第一款Android應用程序了。當大家第一次啟動Android Studio時,應該會看到該軟體的歡迎屏幕,其中還提供一些選項、指導我們以此為起點邁出Android應用開發的第一步。

在今天的教程中,我們將選擇「New Project(新項目)」選項。不過如果大家希望把Eclipse等其它環境中的現有項目轉化為Android Studio項目,也可以選擇「Import Project(導入項目)」。Android Studio能夠將Eclipse項目轉換為Android Studio項目,並在項目中為用戶提供必要的配置文件。
如果大家在選項列表中點擊了「Open Project(打開項目)」,則可以開啟已經利用Android Studio或者IntelliJ IDEA創建出的項目。而選擇「Check out from Version Control(版本控制檢查)」的話,大家能夠對處於版本控制之下的項目副本進行檢查。通過這種方式,我們可以將現有項目作為基礎、快速構建起新的針對性版本。
由於我們需要從零開始,因此這里選擇「新項目」。這時大家會看到一份選項列表,旨在對我們的新項目作出配置。在今天的教程中,我們將創建一款簡單的應用程序,主要目的是為大家演示Android Studio中最為重要的一部分功能特性。相信大家也和我一樣,會認為「HelloWorld」這個名稱最適合本次開發出的新項目。

正如大家在上面這幅截圖中所看到,我把自己的應用程序命名為HelloWorld,並為其設定了模塊名稱。如果大家對IntelliJ IDEA不太熟悉,可能不知道模塊這東西到底是什麼。模塊實際上就是一個可以進行編譯、運行、測試以及調試的獨立功能單元。模塊當中包含有源代碼、編譯腳本以及用於特定任務的其它組成部分。
在創建新項目時,大家還可以為該項目設定軟體包名稱。在默認情況下,Android Studio會將項目包名稱的最後一項元素設置為模塊名稱,但只要願意、大家可以隨意對其作出變更。
其它設定內容還包括項目在設備上的保存位置、最低與推薦SDK、項目編譯需要使用的SDK以及項目主題等等。大家也可以要求Android Studio創建一個Activity類、為其自定義一個啟動圖標,或者設定該項目是否支持GridLayout、Fragments、Navigation Drawer或者Action Bar等。
這里我們不會為自己的應用程序創建自定義圖標,因此大家可以取消「Create custom launch icon(創建自定義啟動圖標)」項目前的勾選框。點擊「Next(下一步)」繼續進行其它項目設置步驟。
由於我們在之前的步驟中勾選了「Create activity(創建activity)」項目的勾選框,因此這里導航會要求大家對Android Studio將為我們創建的Activity類進行配置。

由於我們將從空白Activity類開始進行配置,因此大家可以點擊「Next」執行設置流程的下面幾個步驟。這里大家需要對該Activity類、主布局以及片段布局進行命名。大家也可以設置導航類型,在今天的示例項目中我們將其設置為「None」。下面這幅截圖顯示的是我們的設置方案看起來是什麼樣子。

在點擊「Finish」之後,大家會看到如下圖所示的Android Studio用戶界面。其中窗口左側為項目資源管理器,右側則為工作區。在Android Studio中對項目進行設置之後,現在我們可以逐一查看Android Studio當中的各項關鍵功能。

2. Android虛擬設備
所謂Android虛擬設備——或者簡稱AVD——是一套模擬器配置方案,它允許大家設定出與實際情況相符的Android設備型號。這就讓開發者在多種多樣的設備平台上運行並測試應用程序變得更為輕松。在Android虛擬設備功能的支持下,大家可以為Android模擬器指定需要模擬的硬體與軟體組合。
創建Android虛擬設備的首選方式是通過AVD Manager。大家可以在Android Studio用戶界面的Tools菜單中依次選擇Android〉AVD Manager。

如果大家之前對開發環境的設置工作正確無誤,那麼Android虛擬設備管理器的界面應該如下圖所示。

要創建新的AVD,我們需要點擊右側的「New…」、為AVD設定名稱並如下圖所示對虛擬設備進行配置。最後點擊「OK」以創建自己的第一套AVD。

要使用我們剛剛創建好的AVD,首先需要在AVD管理器的列表中將其選中,然後點擊窗口右側的「Start…」。如果大家的AVD設置過程正確無誤,那麼Android模擬器在啟動後應該如下圖所示。

既然Android模擬器已經成功啟動並開始運行,現在是時候啟動我們的應用程序了。在「Run」菜單中選擇「Run 『helloworld』」——沒錯,在Android模擬器中運行應用程序就是這么簡單。

3.實時布局(Live Layout)
Android Studio中的實時布局功能允許大家在無需將應用程序運行在設備或者模擬器中的前提下,直接預覽應用的用戶界面。實時布局是一款極為強大的工具,能夠幫助開發者節約大量時間。在實時布局的幫助下,查看應用程序用戶界面的任務變得輕松而且快捷。
要使用實時布局,我們需要雙擊對應XML布局文件並選擇工作區下方的「Text」標簽。接下來選擇工作區右側的「Preview」標簽來預覽當前布局。我們對XML布局作出的任何變更都會直接反映在右側的預覽窗口當中。大家可以查看下面這幅截圖來深入理解這項功能。

實時布局功能為我們帶來了諸多值得稱道的顯著優勢。舉例來說,大家可以在Preview面板的第一項菜單中選擇選項,從而對當前正在使用的XML布局隨意作出調整。譬如說,大家可以分別創建不同的縱向與橫向顯示視圖,Android Studio會承擔起創建必要文件夾及文件的任務。
Preview面板中的第二項菜單允許大家變更顯示在Preview面板內的設備大小。第三項菜單的作用則是調整設備在Preview面板中的朝向,這樣我們就能更輕松地查看同一套布局方案在不同顯示模式(縱向與橫向)下的效果與主題。
Preview面板中的第四項菜單允許我們輕松訪問Activity或者布局所使用的個別片段。Preview面板還允許大家變更在實時布局中使用的語言,從而輕松預覽不同語言在布局方案中的顯示效果。最右邊的菜單的作用則是調整API版本。
Preview面板中還包含多項控制機制,例如對布局進行縮放、重新Preview面板或者截取當前屏幕。
4.模板
Android Studio還為開發人員提供多種模板選項,從而大大提升開發速度。這些模板能自動創建Activity以及必要的XML文件。大家還可以利用這些模板創建出較為基礎的Android應用程序,並將其運行在實體設備或者模擬器當中。
在Android Studio當中,我們可以在創建新的Activity時一同創建出對應模板。右鍵點擊窗口左側項目瀏覽器中的「package name」並在菜單中選擇「New」,而後從選項列表中點選「Activity」。Android Studio隨後會為開發者列出模板清單,其中包括Blank Activity、Fullscreen Activity以及Tabbed Activity。

大家還可以從菜單中選擇「Image Asset」,接下來的向導會指引我們一步步完成創建流程。下面讓我們一起來看看如何以Login Activity模板為基礎創建一套新的Activity。首先在Acivity模板列表中選擇Login Activity選項以啟動創建向導。

如大家在上面的截圖中所見,我已經將新建的Activity命名為LoginActivity——也就是為activity login設定Layout Name——並為該Activity添加了一個名為Sign In的標題。在默認情況下,對話框中的Include Google+ sign in項目已經被勾選。由於我們不打算在今天的示例中使用Google+登錄功能,因此取消該勾選項。
大家可以選擇為這套新的Activity設定Hierarchical Parent(分層結構)。這樣當我們點擊設備上的後退按鈕時,應用就將通過導航返回至上一界面。我們將這一欄位留空。在點擊「Finish」之後,Android Studio會為我們創建出必要的文件及文件夾。如果一切進展順利,我們將在項目當中看到新的Activity與Layout。
下一布工作是在manifest文件中對新Activity進行設置,這樣它就能在應用程序啟動時作為主Activity加以使用了。請大家一起來看下面的manifest文件內容,其中LoginActivity類擁有自己的活動節點。
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.tuts.HelloWorld.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.tuts.HelloWorld.LoginActivity"
android:label="@string/title_activity_login"
android:windowSoftInputMode="adjustResize|stateVisible" >
</activity>
</application>

為了在應用程序當中啟動我們剛剛創建的LoginActivity,首先需要移除原有LoginActivity類的活動節點,然後利用com.tuts.HelloWorld.LoginActivity代替先前的com.tuts.HelloWorld.MainActivity。這樣一來,應用程序現在就將使用LoginActivity類作為其主Activity。
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="za.co.helloworld.LoginActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

當我們在模擬器當中創建並運行自己的應用程序時,首先應該會看到如下圖所示的顯示內容。這意味著我們已經成功利用剛剛創建的LoginActivity類取代了原有的空白Activity類。

5.Lint工具
對代碼進行測試是一回事,但同樣重要的是、我們還需要在編寫代碼的同時引入各種最佳實踐。這不僅能夠顯著改進性能表現,也能增加應用程序的整體穩定性。另外,經過合理結構調整的項目在維護方面也更為輕松。
Android Studio中提供的Android Lint是一款靜態分析工具,它負責對項目源代碼加以分析。它能夠檢測出應用程序中的潛在漏洞以及其它可能被編譯器所忽略的其它代碼問題。
就以下面這幅截圖為例,大家可以看到該布局中的LinearLayout並未得到實際使用。Android Lint的優勢在於,它能幫助我們重視警告或報錯信息的出現原因,從而更輕松地修復或者解決這些問題。

請大家養成重復使用Android Studio Lint工具的好習慣,這能幫助我們准確檢測到項目當中存在的潛在問題。Lint工具甚至能告訴我們應用程序中是否存在重復的圖片或者編譯內容。
要運行Lint工具,大家首先需要在Android Studio的「Analyze」菜單中選擇「Inspect Code…」。當Android Studio完成了對項目的檢測之後,它會在窗口底部顯示出分析結果。請注意,除了Android Lint之外,Android Studio還提供一系列其它檢查功能。只需雙擊某個已經發現的問題,系統就會幫助大家定位到對應文件中存在問題的位置。

6.富布局編輯器
Android Studio提供一套富布局編輯器,大家可以在其中隨意拖拽各類用戶界面組件。大家還可以在多屏幕配置中同時查看多種布局的顯示效果,這一點我們在前文中已經提到過。
這款富布局編輯器在使用方面非常直觀簡單。我們首先需要一套要處理的布局方案。瀏覽到項目中res文件夾下的layout文件夾,右鍵點擊layout文件夾,然後在彈出的菜單中選擇New>Layout resource file。
下面為新布局設定一個名稱與root元素,而後點擊「OK」。Android Studio會自動在窗口右側的編輯器當中打開該布局。

在編輯器的底部,大家會看到兩個標簽,分別是Design與Text。點擊Text標簽後編輯器將被激活,這樣我們就能對當前選定的布局方案作出變更。
點擊Design標簽則會激活另一套編輯器內容,其中顯示出布局的預覽效果。要向布局當中添加其它功能性組件,我們只需將其從布局左側的組件列表中拖出並放入布局內即可。是的,就這么簡單。

『柒』 Android單元測試都是測一些什麼

單元測試(unit testing),是指對軟體中的最小可測試單元進行檢查和驗證。對於單元測試中單元的含義,一般來說,要根據實際情況去判定其具體含義,如C語言中單元指一個函數,Java里單元指一個類,圖形化的軟體中可以指一個窗口或一個菜單等。總的來說,單元就是人為規定的最小的被測功能模塊。單元測試是在軟體開發過程中要進行的最低級別的測試活動,軟體的獨立單元將在與程序的其他部分相隔離的情況下進行測試。
在一種傳統的結構化編程語言中,比如C,要進行測試的單元一般是函數或子過程。在像C++這樣的面向對象的語言中, 要進行測試[1] 的基本單元是類。對Ada語言來說,開發人員可以選擇是在獨立的過程和函數,還是在Ada包的級別上進行單元測試。單元測試的原則同樣被擴展到第四代語言(4GL)的開發中,在這里基本單元被典型地劃分為一個菜單或顯示界面。
經常與單元測試聯系起來的另外一些開發活動包括代碼走讀(Code review),靜態分析(Static analysis)和動態分析(Dynamic analysis)。靜態分析就是對軟體的源代碼進行研讀,查找錯誤或收集一些度量數據,並不需要對代碼進行編譯和執行。動態分析就是通過觀察軟體運行時的動作,來提供執行跟蹤,時間分析,以及測試覆蓋度方面的信息。

『捌』 分析程序軟體您覺得通過哪些方式有幾種辦法可以實現

方法通過靜態分析方式和動態分析方式相結合,實現應用程序行為分析檢測。靜態分析通過Android的靜態反匯編和反編譯獲取應用程序的源代碼和資源配置文件,然後通過檢測源代碼中是否包含敏感行為特徵,實現靜態行為分析檢測。動態分析結合沙箱系統,實現程序的動態運行並輸出行為日誌,然後對輸出的行為日誌分析,實現對應用程序動態行為分析檢測。靜態分析由於某些程序精心構造,無法對一些未將特徵編碼在代碼文件中行為進行分析,在檢測時無法獲取潛在的應用程序行為;動態分析由於自動運行行為的隨機性,不能完全觸發應用程序操作。兩種方式都存在這不足,所以本課題在實現分析系統時採取了動靜態分析相結合方式,以更全面的實現Android應用程序的行為分析檢測,為安全分析提供依據。

『玖』 如何分析android的oom,與java靜態代碼分析工具

在Android平台上面,應用程序OOM異常永遠都是值得關注的問題。通常這一塊也是程序這中的重點之一。這下我就如何解決OOM作一點簡單的介紹。
首先,OOM就是內存溢出,即Out Of Memory。也就是說內存佔有量超過了VM所分配的最大。
怎麼解決OOM,通常OOM都發生在需要用到大量內存的情況下(創建或解析Bitmap,分配特大的數組等),在這樣的一種情況下,就可能出現OOM,據我現在了解到,多數OOM都是因為Bitmap太大。所以,這里我就專門針對如何解決Bitmap的OOM。其實最核發的就是只載入可見范圍內的Bitmap,試想這樣一種情況,在GridView或ListView中,數據量有5000,每一屏只顯示20個元素,那麼不可見的,我們是不需要保存Bitmap在內在中的。所以我們就是只把那麼可見的Bitmap保留在內存中,那些不可見的,就釋放掉。當元素滑出來時,再去載入Bitmap。
這里我有兩種方式,都可以避免OOM。
一,主動釋放Bitmap的內存
這種方式我簡單說一下,不太推薦,這也是我最開始使用的一種方法,但最後證明它不是最好的。(不推薦)
它的本質思路是:
1、只載入可見區域的Bitmap
2、滑動時不載入
3、停止滑動(Idle)後,開始重新載入可見區域的圖片
4、釋放滑出可見區域的Bitmap的內在。
它比較復雜:
1、我們需要監聽GridView/ListView的滑動事件,這個很簡單做到,AbsListView#setOnScrollListener(OnScrollListener l)
2、主動調用Bitmap#recycle()方法,它會導致一個問題,必須判斷這個Bitmap是否被一個View(ImageView等)所引用,如果被引用,我們不能簡單地調用recycle()方法,這樣會導致異常,說是View使用了一個已經被回收的Bitmap。
3,我們必須設計自己的線程來控制開始/暫停等,因為GridView/ListView的滑動狀態可能不斷地變化,也就是說滑動->停止->滑動,這種狀態可能不斷變化,這樣就會導致我們的線程中的run()方法裡面的邏輯比較復雜,一旦復雜,問題就可能就得更多。
基於以上幾點,這種方式不是最好的,所以不推薦。
二,設計Cache
這種方式,我覺得是比較好的一種,它首先利用了cache,我認為cache是一個很重要的東西,把Bitmap的內存單獨放在一個地方來管理,這個地方就是cache,它的容量是一定的,我們可能會不斷的向這個cache中添加元素,也可能不斷的移除元素。
為了更好的說明這種方式,先要介紹一下LruCache。
LruCache
1、這其實就是一個LinkedHashMap,任意時刻,當一個值被訪問時,它就會被移動到隊列的開始位置,所以這也是為什麼要用LinkedHashMap的原因,因為要頻繁的做移動操作,為了提高性能,所以要用LinkedHashMap。當cache滿了時,此時再向cache裡面添加一個值,那麼,在隊列最後的值就會從隊列裡面移除,這個值就有可能被GC回收掉。

『拾』 靜態分析是指

經濟領域概念
靜態分析是一種分析經濟現象的均衡狀態以及有關的經濟變數達到均衡狀態所需要條件的分析方法。[1]而不考慮經濟現象達到均衡狀態的過程,它完全抽象掉了時間因素和具體的變化過程,是一種靜止地、孤立地考察某種經濟事物的方法。
網路


靜態分析
經濟領域概念
靜態分析是一種分析經濟現象的均衡狀態以及有關的經濟變數達到均衡狀態所需要條件的分析方法。[1]而不考慮經濟現象達到均衡狀態的過程,它完全抽象掉了時間因素和具體的變化過程,是一種靜止地、孤立地考察某種經濟事物的方法。

中文名
靜態分析
外文名
static analysis
指標
總量指標、相對指標、平均指標、標志變異指標等
應用
靜態計算機科學、經濟學、工程、力學、機械
釋義
根據既定的外生變數值求得內生變數的分析方法
內涵
靜態分析法是根據既定的外生變數值求得內生變數的分析方法,是對已發生的經濟活動成果,進行綜合性的對比分析的一種分析方法。

如研究均衡價格時,舍掉時間、地點等因素,並假定影響均衡價格的其他因素,如消費者偏好、收入及相關商品的價格等靜止不變,單純分析該商品的供求達於均衡狀態的產量和價格的決定。簡單地說就是抽象了時間因素和具體變動的過程,靜止地孤立地考察某些經濟現象。它一般用於分析經濟現象的均衡狀態以及有關經濟變數達到均衡狀態所需要的條件。

常用的靜態分析法有:相對數分析法、平均數分析法、比較分析法、結構分析法、因素替換分析法、綜合計算分析法、價值系數分析法等。

指標

熱點內容
熱雲伺服器 發布:2025-03-10 17:02:36 瀏覽:994
cpp1新建編譯 發布:2025-03-10 17:00:14 瀏覽:226
走水標高演算法 發布:2025-03-10 17:00:07 瀏覽:787
伺服器更新地址之後登錄不上 發布:2025-03-10 16:36:29 瀏覽:706
資料庫前端 發布:2025-03-10 16:23:47 瀏覽:417
當腳本運行後 發布:2025-03-10 16:18:50 瀏覽:845
如何確認自己的手機型號安卓 發布:2025-03-10 16:11:31 瀏覽:23
linux系統命令及shell 發布:2025-03-10 16:09:55 瀏覽:763
配送寶源碼 發布:2025-03-10 16:07:08 瀏覽:633
安卓wifi路由器在哪裡看 發布:2025-03-10 15:47:09 瀏覽:269