溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

代碼的性能優化,5方面的調優經驗

發布時間:2020-03-30 21:27:07 來源:網絡 閱讀:426 作者:Java筆記丶 欄目:編程語言

前言

前一段時間一直在做性能調優的工作,頗有收獲。因此,簡單的總結并分享下研究成果。性能調優很有趣但也是個無底洞,不可能在一篇文章全部闡述完。這里只是提供一個方向,以后碰到了知道可以從這些方面入手即可。具體如下:

代碼的性能優化,5方面的調優經驗


代碼層面

for循環中不要利用 + 號去拼接字符串

在循環次數比較多的for循環中,我們也不要利用 + 號去拼接字符串。具體例子如下:


程序清單?1-1@Testpublic?void?test(){
????String?str?=?"ay";
????for(int?i=0;i<Integer.MAX_VALUE;i++){
?????????str?=?str?+?i;
????}}


具體解決方法如下:

根據具體的業務場景,使用 StringBuffer(線程安全)或者 StringBuilder(非線程安全)

使用數組

程序清單?1-1@Testpublic?void?test(){
????//第一種解決方法????StringBuilder?stringBuilder?=?new?StringBuilder(Integer.MAX_VALUE);
????//第二種解決方法????String[]?strArray?=?new?String[Integer.MAX_VALUE?+?1];
????stringBuilder.append("ay");
????strArray[0]?=?"ay";
????for(int?i=0;i<Integer.MAX_VALUE?+?1;i++){
????????stringBuilder.append("al");
????????strArray[i?+?1]?=?"al";
????}
????System.out.println(stringBuilder.toString());
????System.out.println(ArrayUtils.toString(strArray));}


設置容量參數提高系統性能

對于 StringBuffer(線程安全)或者 StringBuilder(非線程安全),都有相應的構造方法:


程序清單?1-1public?StringBuilder(int?capacity)?{
????super(capacity);}


如果我們可以事先知道需要拼接的字符串長度,設置容量參數,防止 StringBuffer 在源碼內部進行一系列復雜的內存復制操作,影響性能。

如上面的

StringBuilder?stringBuilder?=?new?StringBuilder(Integer.MAX_VALUE);

for循環建議寫法

for?(int?i?=?0,?int?length?=?list.size();?i?<?length;?i++)

方法的返回值

返回List:

private?List<PcsTaskDTO>?sortDecisionAndBackTask(List<PcsTaskDTO>?pcsTaskDTOList)?throws?Exception{
????????if(CollectionUtils.isEmpty(pcsTaskDTOList))?return?null;}

解決方法:

private?List<PcsTaskDTO>?sortDecisionAndBackTask(List<PcsTaskDTO>?pcsTaskDTOList)?throws?Exception{
????????if(CollectionUtils.isEmpty(pcsTaskDTOList))?return?Collections.EMPTY_LIST;}

返回Set:

Collections.EMPTY_SET

返回Map:

Collections.EMPTY_MAP

返回Boolean:

Boolean.TRUE

不要再for循環中查詢數據庫

解決:

  • 根據業務場景,把for循環中的多次連接數據庫查詢,寫到sql中去查詢,既一次性查詢出來

  • 根據業務場景,看是否可以利用緩存,提高查詢效率

去掉System.out.println

代碼部署到生產環境前,去掉全部System.out.println

四種數組復制方式的性能比較和抉擇

數組copy有很多種方法,效率不一。我們先看下面具體實例:

程序清單?2-1????/**?*?測試4種數組復制效率比較?*?@author?阿毅?*?@date?2017/2/7.?*/public?class?AyTest?{
????private?static?final?byte[]?buffer?=?new?byte[1024*10];
????static?{
????????for?(int?i?=?0;?i?<?buffer.length;?i++)?{
????????????buffer[i]?=?(byte)?(i?&?0xFF);
????????}
????}
????private?static?long?startTime;

????public?static?void?main(String[]?args)?{
????????startTime?=?System.nanoTime();
????????byte[]?newBuffer?=?new?byte[buffer.length];
????????for(int?i=0;i<buffer.length;i++)?{
????????????newBuffer[i]?=?buffer[i];
????????}
????????calcTime("forCopy");

????????startTime?=?System.nanoTime();
????????byte[]?newBuffer2?=?buffer.clone();
????????calcTime("cloneCopy");

????????startTime?=?System.nanoTime();
????????byte[]?newBuffer3?=?Arrays.copyOf(buffer,?buffer.length);
????????calcTime("arraysCopyOf");

????????startTime?=?System.nanoTime();
????????byte[]?newBuffer4?=?new?byte[buffer.length];
????????System.arraycopy(buffer,?0,?newBuffer,?0,?buffer.length);
????????calcTime("systemArraycopy");
????}

????private?static?void?calcTime(String?type)?{
????????long?endTime?=?System.nanoTime();
????????System.out.println(type?+?"?cost?"?+(endTime-startTime)+?"?nanosecond");
????}}


運行結果:

forCopy?cost?711576?nanosecondcloneCopy?cost?53490?nanosecondarraysCopyOf?cost?119946?nanosecondsystemArraycopy?cost?39712?nanosecond


多運行幾次,我們得出數組復制效率:

System.arraycopy > clone > Arrays.copyOf > for

綜上所述,當復制大量數據時,使用System.arraycopy()命令。


8.實現高性能的字符串分割

實現字符串的分割的方法有很多種,常用的是 split ,StringTokenizer ,indexOf 和 substring 的配合,以及一些開源工具類,如:StringUtils。它們各有優缺。

@Testpublic?void?test(){
????//數據初始化????StringBuffer?sb?=?new?StringBuffer();
????for(int?i=0;i<10000;i++){
????????sb.append(i).append(";");
????}
????String?originStr?=?sb.toString();
????//第一種分隔字符方法????long?startTime?=?System.nanoTime();

????String[]?splitArray?=??originStr.split(";");
????for(int?i=0,len?=?splitArray.length;i<len;i++){
????????String?temp?=?splitArray[i];
????}
????long?endTime?=?System.nanoTime();
????System.out.println("the?cost?of?split?is?:"?+?(endTime?-?startTime));
????//第二種分隔字符方法????System.out.println("--------------------------------------------");
????originStr?=?sb.toString();
????startTime?=?System.nanoTime();
????StringTokenizer?st?=?new?StringTokenizer(originStr,";");
????while(st.hasMoreTokens()){
????????st.nextToken();
????}
????endTime?=?System.nanoTime();
????System.out.println("the?cost?of?stringTokenizer?is?:"?+?(endTime?-?startTime));
????//第三種分隔字符的方法????System.out.println("--------------------------------------------");
????originStr?=?sb.toString();
????startTime?=?System.nanoTime();
????while?(true){
????????int?index?=?originStr.indexOf(";");
????????if(index?<?0)?break;
????????String?origin?=?originStr.substring(0,index);
????????originStr?=?originStr.substring(index?+?1);
????}
????endTime?=?System.nanoTime();
????System.out.println("the?cost?of?indexOf?is?:"?+?(endTime?-?startTime));

????//第四種分隔字符的方法????System.out.println("--------------------------------------------");
????originStr?=?sb.toString();
????startTime?=?System.nanoTime();
????String[]?utilSplit?=?StringUtils.split(originStr,';');
????for(int?i=0,len?=?utilSplit.length;i<len;i++){
????????String?temp?=?utilSplit[i];
????}
????endTime?=?System.nanoTime();
????System.out.println("the?cost?of?StringUtils.split?is?:"?+?(endTime?-?startTime));}


運行結果:

the?cost?of?split?is?:35710479--------------------------------------------the?cost?of?stringTokenizer?is?:11992643--------------------------------------------the?cost?of?indexOf?is?:323050471--------------------------------------------the?cost?of?StringUtils.split?is?:59026333


從上面例子可以看出,字符分割的性能,由高到低的排序為:StringTokenizer > split ,StringUtils.split > indexOf 。有些書籍寫著 indexOf 的性能是最高的,但是按照我的測試,index的性能是最差的。但是事物都有兩面性,從上面的例子也可以看出,雖然 StringTokenizer 的性能高,但是代碼量多,可讀性差,而 split 代碼相對就整潔多了。

切勿把異常放置在循環體內

try-catch語句本身性能不高,如果再放到循環體中,無非是雪上加霜。因此在開發中,我們要極力避免。

例:

for(int?i=0;i<10;i++){
????try{
????}catch?(Exception?e){
????}}


正確做法:

try{
????for(int?i=0;i<10;i++){
????}}catch?(Exception?e){}


綜上所述:不要再循環體內執行復制,耗時的操作。

盡量縮小鎖的范圍

鎖優化的思路和方法總結一下,有以下幾種。

  • 減少鎖持有時間(盡量縮小鎖的范圍)

  • 減小鎖粒度

  • 鎖分離

  • 鎖粗化

  • 鎖消除

我們應該確保我們只在必要的地方加鎖,將鎖從方法聲明移到方法體中會延遲鎖的加載,進而降低了鎖競爭的可能性。先看下面的實例:

class?SynObj?{
????//方法鎖/或者對象鎖????public?synchronized?void?methodA()?{
????????System.out.println("methodA.....");
????????try?{
????????????Thread.sleep(5000);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????}

????public??void?methodB()?{
????????//對代碼塊進行鎖,降低鎖的競爭????????synchronized(this)?{
????????????System.out.println("methodB.....");
????????}
????}

????public?void?methodC()?{
????????String?str?=?"sss";
????????//這里鎖的是?str?這個對象,而不是?SynObj?對象????????synchronized?(str)?{
????????????System.out.println("methodC.....");
????????}
????}}/**?*?Created?by?Ay?on?2017/3/26.?*/public?class?AyTest?{

????public?static?void?main(String[]?args)?{
????????final?SynObj?obj?=?new?SynObj();

????????Thread?t1?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????obj.methodA();
????????????}
????????});
????????t1.start();

????????Thread?t2?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????obj.methodB();
????????????}
????????});
????????t2.start();

????????Thread?t3?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????obj.methodC();
????????????}
????????});
????????t3.start();
????}}


打印結果:

methodA.....methodC.....//methodB會隔一段時間才會打印出來methodB.....

總結:因為,一個線程訪問了 synchronized 同步代碼塊中的代碼,另一個線程不可以訪問該對象的任何同步代碼塊,但可以訪問非同步代碼塊。所有縮小鎖的范圍可以在一定程度上提高代碼性能。

鎖分離

最常見的鎖分離就是讀寫鎖ReadWriteLock,根據功能進行分離成讀鎖和寫鎖,這樣讀讀不互斥,讀寫互斥,寫寫互斥,即保證了線程安全,又提高了性能。

還有就是網上一個高手寫的一個例子:

public?class?Grocery?{
????private?final?ArrayList?fruits?=?new?ArrayList();
????private?final?ArrayList?vegetables?=?new?ArrayList();
????//對象鎖,不好,效率低????public?synchronized?void?addFruit(int?index,?String?fruit)?{
????????fruits.add(index,?fruit);
????}
????//對象鎖,不好,效率低????public?synchronized?void?removeFruit(int?index)?{
????????fruits.remove(index);
????}
????//對象鎖,不好,效率低????public?synchronized?void?addVegetable(int?index,?String?vegetable)?{
????????vegetables.add(index,?vegetable);
????}
????//對象鎖,不好,效率低????public?synchronized?void?removeVegetable(int?index)?{
????????vegetables.remove(index);
????}}


優化后:

public?class?Grocery?{
????private?final?ArrayList?fruits?=?new?ArrayList();
????private?final?ArrayList?vegetables?=?new?ArrayList();
????public?void?addFruit(int?index,?String?fruit)?{
????????//水果鎖?
????????synchronized(fruits)?fruits.add(index,?fruit);
????}
????public?void?removeFruit(int?index)?{
????????//水果鎖?
????????synchronized(fruits)?{fruits.remove(index);}
????}
????public?void?addVegetable(int?index,?String?vegetable)?{
????????//蔬菜鎖????????synchronized(vegetables)?vegetables.add(index,?vegetable);
????}
????public?void?removeVegetable(int?index)?{
????????//蔬菜鎖????????synchronized(vegetables)?vegetables.remove(index);
????}}


文件導入導出注意使用緩存流

批量插入數據性能優化

1.1 問題一

直接批量保存3萬多條數據。

List<PcsTestcase>?pcsTestcases?=?new?ArrayList<>();//?......//直接調用批量保存??
this.batchCreate(pcsTestcases);

1.2 問題二

批量保存時,利用UUID生成工具,給主鍵設置Id。找出Hibernate的先查詢后更新的機制觸發,造成不必要的查詢損耗。

List<PcsTestcase>?pcsTestcases?=?new?ArrayList<>();PcsTestcase?pcsTestcase?=?null;for?(int?j?=?sheet.getFirstRowNum()?+?1,len?=?sheet.getLastRowNum();?j?<=?len;j++)?{
????Row?row?=?sheet.getRow(j);
????if?(row?==?null)?continue;
????pcsTestcase?=?new?PcsTestcase();
????//看這里,重要:這里在插入數據時,設置主鍵Id????pcsTestcase.setId(UUIDUtils.generate());
????pcsTestcase.setPmMilestoneId(pcsMainTask.getId());}

1.1 問題一解決方法

對于問題二,我們可以把所有數據,每500條進行一次批量保存操作,速度會比一次性批量保存好。具體如下:

if(j?%?500?==?0?||?j?==?len){
????this.batchCreate(pcsTestcases);
????pcsTestcases?=?new?ArrayList<>();
}

1.2 問題二解決方法

對于問題三,由于Hibernate在進行插入時,會判斷數據是進行插入還是進行更新。如果模型的主鍵不為空,查詢數據后,再進行更新數據,否則,進行插入數據操作。因此,我們在進行插入操作時候,不要設置模型的主鍵,可以避免不必要查詢消耗。

pcsTestcase.setId(UUIDUtils.generate());

業務層面

  • 減少前端請求數

  • 過度復用方法帶來的性能問題

  • 后端如果需要一次性加載數據,防止多次請求數據庫

數據庫層面

SQL語句大小寫規范

我們在寫SQL的時候,通常會出現大小寫混用的情況。如下:

select?*?FROM?pm_testcase?pt?where?pt.Name?=?'ay'

正確的做法是SQL語句全部大寫或者全部小寫。如下:

--?全部小寫
select?*?from?pm_testcase?pt?where?pt.name?=?'ay'

--?全部大寫
SELECT?*?FROM?PM_TESTCASE?PT?WHERE?PT.NAME?=?'ay'

PostgreSQL執行計劃

PostgreSQL的執行計劃,做為數據庫性能調優的利器,有必要在開頭簡單的介紹下。

explain?analyse?select?*?from?pm_testcase?pt
--執行計劃
Seq?Scan?on?pm_testcase?pt??(cost=0.00..5237.11?rows=60011?width=2020)?(actual?time=37.347..435.601?rows=60012?loops=1)
Planning?time:?0.426?ms
Execution?time:?438.442?ms

cost說明:

  • 第一個數字0.00表示啟動cost,這是執行到返回第一行時需要的cost值。

  • 第二個數字4621.00表示執行整個SQL的cost

通過查看執行計劃,我們就能夠找到SQL中的哪部分比較慢,或者說花費時間多。然后重點分析哪部分的邏輯,比如減少循環查詢,或者強制改變執行計劃。

更多執行計劃 Explain,可網上搜索。

建立索引避免全表掃描

首先,在數據庫里有一張表 pm_testcase,里面有150萬條數據。

如下SQL,我們利用執行計劃,對創建時間(created_time)進行排序,輸出執行計劃結果。

程序清單?2-1explain?select?*?from?pm_testcase?ptorder?by?pt.created_time?desc--Sort??(cost=4103259.72..4107084.44?rows=1529885?width=1920)--Sort?Key:?created_time--->??Seq?Scan?on?pm_testcase?pt??(cost=0.00..134087.85?rows=1529885?width=1920)

cost=說明:

第一個數字4103259.72表示啟動cost,這是執行到返回第一行時需要的cost值。

第二個數字4107084.44表示執行整個SQL的cost。

該語句總共耗時 4107084.44

這里我們創建 created_time 索引,對相同語句執行 程序清單 2-1 的SQL,得到的執行計劃結果為:

Index?Scan?Backward?using?idx_create_time?on?pm_testcase?pt??(cost=0.43..384739.28?rows=1530024?width=1920)

很明顯,執行整個SQL的 cost 由 4107084.44 減少到 384739.28

因此,為了避免全表掃描,建議在考慮在 where 及 order by 涉及的列上建立索引。

防止索引失效

我們應盡量避免在 where 子句中使用 != 或 <> 操作符,否則引擎將放棄使用索引而進行全表掃描。

如下例子,我們在 pm_testcase 的 code 上添加了索引:

explain?select?pt.code?from?pm_testcase?ptwhere?pt.code?!=?'case005510'--執行計劃,Seq?Scan?全表掃描Seq?Scan?on?pm_testcase?pt??(cost=0.00..137914.30?rows=1529973?width=11)explain?select?pt.code?from?pm_testcase?ptwhere?pt.code?=?'case005510'--執行計劃,Bitmap?Heap?Scan?索引掃描Bitmap?Heap?Scan?on?pm_testcase?pt??(cost=4.82..206.29?rows=51?width=11)

通過上面的例子可以看出,!= 操作符使得索引失效。

避免建立太多的索引

索引并不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 和 update 的效率,因為 insert 或 update 時有可能會重建索引,所以視具體情況而定。一個表的索引數最好不要超過7個,若太多則應考慮一些不常使用到的列上建的索引是否有必要.

關于查詢效率的幾點建議

  • 盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。

  • 盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為變長字段存儲空間小,對于查詢來說,在一個相對較小的字段內搜索效率顯然要高些。

  • 最好不要給數據庫留NULL,盡可能的使用 NOT NULL填充數據庫。備注、描述、評論之類的可以設置為 NULL。其他的,最好不要使用NULL。

  • 任何地方都不要使用 select * from t ,用具體的字段列表代替 * ,不要返回用不到的任何字段。

  • 應盡量避免在 where 子句中使用 or 來連接條件,可以考慮使用 union 代替

  • in 和 not in 也要慎用。對于連續的數值,能用 between 就不要用 in,exists 代替 in

  • 盡量避免在 where 子句中對字段進行表達式操作和函數操作

在Join表的時候字段使用相同類型,并將其索引

如果你的應用程序有很多JOIN查詢,你應該確認兩個表中Join的字段是被建過索引的。這樣,SQL內部會啟動為你優化Join的SQL語句的機制。而且,這些被用來Join的字段,應該是相同的類型的。例如:如果你要把 DECIMAL 字段和一個 INT 字段 Join 在一起,SQL 就無法使用它們的索引。對于那些STRING 類型,還需要有相同的字符集才行。(兩個表的字符集有可能不一樣)程序員站

優化子查詢

子查詢很靈活可以極大的節省查詢的步驟,但是子查詢的執行效率不高。執行子查詢時數據庫需要為內部嵌套的語句查詢的結果建立一個臨時表,然后再使用臨時表中的數據進行查詢。查詢完成后再刪除這個臨時表,所以子查詢的速度會慢一點。

我們可以使用join語句來替換掉子查詢,來提高效率。join語句不需要建立臨時表,所以其查詢速度會優于子查詢。大部分的不是很復雜的子查詢都可以替換成join語句。

服務器層面

服務器的調優,就得根據客戶提供的真實環境的配置。如服務器是幾核幾個CPU等等。服務器的硬件指標確定下來后,根據指標調整Tomcat,JDK,數據庫,Apatch等配置參數。讓整個環境達到最優的效果。這塊工作一般不是開發人員進行的。但是我們要了解清楚一些配置參數

Tomcat && JDK

  • tomcat 配置

  • JDK垃圾回收機制

  • 垃圾回收機制算法選擇

  • JVM內存模型

Postgresql數據庫配置

Linux服務器

輸出系統日志最后10行 dmesg | tail

ubuntu@ubuntu:~$?dmesg?|?tail[38060.138072]?e1000:?eno16777736?NIC?Link?is?Down[38068.362442]?e1000:?eno16777736?NIC?Link?is?Up?1000?Mbps?Full?Duplex,?Flow?Control:?None[38070.366445]?e1000:?eno16777736?NIC?Link?is?Down[38076.376947]?e1000:?eno16777736?NIC?Link?is?Up?1000?Mbps?Full?Duplex,?Flow?Control:?None[38084.386812]?e1000:?eno16777736?NIC?Link?is?Down[38090.411818]?e1000:?eno16777736?NIC?Link?is?Up?1000?Mbps?Full?Duplex,?Flow?Control:?None[38480.597723]?e1000:?eno16777736?NIC?Link?is?Down[38495.064487]?e1000:?eno16777736?NIC?Link?is?Up?1000?Mbps?Full?Duplex,?Flow?Control:?None[38607.910407]?IPv6:?ADDRCONF(NETDEV_UP):?eno16777736:?link?is?not?ready[38607.978329]?e1000:?eno16777736?NIC?Link?is?Up?1000?Mbps?Full?Duplex,?Flow?Control:?None

命令會輸出系統日志的最后10行。這些日志可以幫助排查性能問題。

top命令

top命令是進行性能分析最常使用的命令,也是最重要的命令。每個參數代表什么意思,都必須非常清楚。

top?-?07:01:15?up?10:57,??3?users,??load?average:?0.00,?0.04,?0.13Tasks:?238?total,???1?running,?237?sleeping,???0?stopped,???0?zombie%Cpu(s):??3.4?us,??3.8?sy,??0.0?ni,?92.8?id,??0.0?wa,??0.0?hi,??0.0?si,??0.0?stKiB?Mem:???2040024?total,??2020312?used,????19712?free,????11220?buffersKiB?Swap:??3142652?total,???927204?used,??2215448?free.???121276?cached?Mem

??PID?USER??????PR??NI????VIRT????RES????SHR?S??%CPU?%MEM?????TIME+?COMMAND???????????????????????????????????????????????????????????????????
?6844?root??????20???0??333020??20520???3600?S???6.0??1.0??29:48.44?Xorg??????????????????????????????????????????????????????????????????????61687?ubuntu????20???0?1635056??43716??18108?S???3.6??2.1???5:00.27?compiz????????????????????????????????????????????????????????????????????
?5444?ubuntu????20???0?3765292?875688??10020?S???2.7?42.9??42:13.69?java??????????????????????????????????????????????????????????????????????
?6788?root??????20???0??293028???9284???1112?S???2.3??0.5???0:51.92?dockerd???????????????????????????????????????????????????????????????????
?5175?ubuntu????20???0??578736??22496??14888?S???1.7??1.1???0:04.60?gnome-terminal-???????????????????????????????????????????????????????????
???27?root??????39??19???????0??????0??????0?S???0.7??0.0???0:09.02?khugepaged????????????????????????????????????????????????????????????????
?7932?ubuntu????20???0?3060636??16560

top命令包含了前面好幾個命令的檢查的內容。比如系統負載情況(uptime)、系統內存使用情況(free)、系統CPU使用情況(vmstat)等。因此通過這個命令,可以相對全面的查看系統負載的來源。同時,top命令支持排序,可以按照不同的列排序,方便查找出諸如內存占用最多的進程、CPU占用率最高的進程等。

但是,top命令相對于前面一些命令,輸出是一個瞬間值,如果不持續盯著,可能會錯過一些線索。這時可能需要暫停top命令刷新,來記錄和比對數據。

第一行:

top?-?07:01:15?up?10:57,??3?users,??load?average:?0.00,?0.04,?0.13

解釋:

07:01:15????當前時間up?10:57????系統運行時間,格式為時:分3?user????當前登錄用戶數load?average:?0.00,?0.04,?0.13????系統負載,即任務隊列的平均長度。三個數值分別為?1分鐘、5分鐘、15分鐘前到現在的平均值。

第二行和第三行,當有多個CPU時,這些內容可能會超過兩行。內容如下:

total?進程總數running?正在運行的進程數sleeping?睡眠的進程數stopped?停止的進程數zombie?僵尸進程數Cpu(s):?3.4%?us?用戶空間占用CPU百分比3.8%?sy?內核空間占用CPU百分比0.0%?ni?用戶進程空間內改變過優先級的進程占用CPU百分比92.8%?id?空閑CPU百分比0.0%?wa?等待輸入輸出的CPU時間百分比0.0%hi:硬件CPU中斷占用百分比0.0%si:軟中斷占用百分比0.0%st:虛擬機占用百分比

最后兩行為內存信息。內容如下:

Mem:2040024?total????物理內存總量2020312?used????使用的物理內存總量17616k?free????空閑內存總量11220?buffers????用作內核緩存的內存量Swap:?3142652?total????交換區總量927204?used????使用的交換區總量2215448?free????空閑交換區總量121276?cached????緩沖的交換區總量,內存中的內容被換出到交換區,而后又被換入到內存,但使用過的交換區尚未被覆蓋,該數值即為這些內容已存在于內存中的交換區的大小,相應的內存再次被換出時可不必再對交換區寫入。

進程信息區統計信息區域的下方顯示了各個進程的詳細信息。首先來認識一下各列的含義。


序號 列名 含義

a????PID?????進程idb????PPID????父進程idc????RUSER???Real?user?named????UID?????進程所有者的用戶ide????USER????進程所有者的用戶名f????GROUP???進程所有者的組名g????TTY?????啟動進程的終端名。不是從終端啟動的進程則顯示為??h????PR??????優先級i????NI??????nice值。負值表示高優先級,正值表示低優先級j????P???????最后使用的CPU,僅在多CPU環境下有意義k????%CPU????上次更新到現在的CPU時間占用百分比l????TIME????進程使用的CPU時間總計,單位秒m????TIME+???進程使用的CPU時間總計,單位1/100秒n????%MEM????進程使用的物理內存百分比o????VIRT????進程使用的虛擬內存總量,單位kb。VIRT=SWAP+RESp????SWAP????進程使用的虛擬內存中,被換出的大小,單位kb。q????RES?????進程使用的、未被換出的物理內存大小,單位kb。RES=CODE+DATAr????CODE????可執行代碼占用的物理內存大小,單位kbs????DATA????可執行代碼以外的部分(數據段+棧)占用的物理內存大小,單位kbt????SHR?????共享內存大小,單位kbu????nFLT????頁面錯誤次數v????nDRT????最后一次寫入到現在,被修改過的頁面數。w????S???????進程狀態(D=不可中斷的睡眠狀態,R=運行,S=睡眠,T=跟蹤/停止,Z=僵尸進程)x????COMMAND?命令名/命令行y????WCHAN???若該進程在睡眠,則顯示睡眠中的系統函數名z????Flags???任務標志,參考?sched.h


查詢登錄當前系統的用戶信息:w命令

ubuntu@ubuntu:~$?w?20:15:44?up?11:17,??3?users,??load?average:?0.21,?0.16,?0.16USER?????TTY??????FROM?????????????LOGIN@???IDLE???JCPU???PCPU?WHATubuntu???:0???????:0???????????????Thu00????xdm???30:09???1.63s?/sbin/upstart?--userubuntu???pts/7????:0???????????????Thu23???45:01m?42:57???8.80s?/home/ubuntu/inno/idea-IU-162.2032.8/bin/fsnotifier64ubuntu???pts/18???:0???????????????06:47????0.00s??0.47s??0.05s?w

可查詢登錄當前系統的用戶信息,以及這些用戶目前正在做什么操作

iostat

運行時,如果出現下面的提示信息

ubuntu@ubuntu:~$?iostatThe?program?'iostat'?is?currently?not?installed.?You?can?install?it?by?typing:sudo?apt-get?install?sysstat

執行下 sudo apt-get install sysstat 即可。

Iostat提供三個報告:CPU利用率、設備利用率和網絡文件系統利用率,使用-c,-d和-h參數可以分別獨立顯示這三個報告。

內存分析命令:free m

ubuntu@ubuntu:~$?free?-m
?????????????total???????used???????free?????shared????buffers?????cachedMem:??????????1992????????672???????1320??????????6?????????22????????209-/+?buffers/cache:????????440???????1552Swap:?????????3068????????403???????2665


free: 查看系統內存的使用情況,-m參數表示按照兆字節展示。

最后兩列分別表示用于IO緩存的內存數,和用于文件系統頁緩存的內存數。需要注意的是,第二行-/+ buffers/cache,看上去緩存占用了大量內存空間。這是Linux系統的內存使用策略,盡可能的利用內存,如果應用程序需要內存,這部分內存會立即被回收并分配給應用程序。因此,這部分內存一般也被當成是可用內存。如果可用內存非常少,系統可能會動用交換區(如果配置了的話),這樣會增加IO開銷(可以在iostat命令中提現),降低系統性能。


查看CPU的占用情況 mpstat

顯示每個CPU的占用情況,如果有一個CPU占用率特別高,那么有可能是一個單線程應用程序引起的。

ubuntu@ubuntu:~$?mpstat?-P?ALL?1Linux?4.2.0-16-generic?(ubuntu)?????04/30/2017??_x86_64_????(2?CPU)10:57:30?PM??CPU????%usr???%nice????%sys?%iowait????%irq???%soft??%steal??%guest??%gnice???%idle10:57:31?PM??all????1.52????0.00????0.51????0.00????0.00????0.51????0.00????0.00????0.00???97.4710:57:31?PM????0????3.03????0.00????0.00????0.00????0.00????0.00????0.00????0.00????0.00???96.9710:57:31?PM????1????0.00????0.00????0.00????0.00????0.00????1.02????0.00????0.00????0.00???98.98


前端

由于我不是做前端的工作,所以沒有太多的經驗總結。不過代碼方面性能優化有些是可以運用到前端。同事也可以減少前端的請求鏈接等等手段去優化。這里由于本人不了解,不做過多的闡述。

免費Java高級資料需要自己領取,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并發分布式等教程,一共30G。? ? ? ? ? ? ??

傳送門:?https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q ?


作者:阿_毅

原文鏈接:blog.csdn.net/huangweny


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女