1. 程式人生 > >程式效能優化(包括資料庫優化、伺服器優化等)

程式效能優化(包括資料庫優化、伺服器優化等)

開心一笑

世界上最互相信任的兩個人應該是初中老師和高中老師了。 
初中老師:這個知識點到高中你們老師會講的,你們現在不必要知道。 
高中老師:這個知識點你們初中老師肯定講過了,我就不講了。 
:你TM在逗我嗎???

提出問題

效能優化時候,應該從哪幾方面入手???

前言

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

效能調優

程式碼層面

for迴圈中不要利用 + 號去拼接字串

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

程式清單 1-1

@Test
public void test(){
    String str = "ay";
    for(int i=0;i<Integer.MAX_VALUE;i++){
         str = str + i;
    }
}

具體解決方法如下:

  • 根據具體的業務場景,使用 StringBuffer(執行緒安全)或者 StringBuilder(非執行緒安全)
  • 使用陣列

    程式清單 1-1
    
    @Test
    public 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-1

public 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 nanosecond
cloneCopy cost 53490 nanosecond
arraysCopyOf cost 119946 nanosecond
systemArraycopy cost 39712 nanosecond

多執行幾次,我們得出陣列複製效率:

System.arraycopy > clone > Arrays.copyOf > for

綜上所述,當複製大量資料時,使用System.arraycopy()命令。

8.實現高效能的字串分割

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

@Test
public 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-1

explain 
select * from pm_testcase pt
order 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 pt
where 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 pt
where 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
[email protected]:~$ 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.13
Tasks: 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 st
KiB Mem:   2040024 total,  2020312 used,    19712 free,    11220 buffers
KiB 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     程序id
b    PPID    父程序id
c    RUSER   Real user name
d    UID     程序所有者的使用者id
e    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+RES
p    SWAP    程序使用的虛擬記憶體中,被換出的大小,單位kb。
q    RES     程序使用的、未被換出的實體記憶體大小,單位kb。RES=CODE+DATA
r    CODE    可執行程式碼佔用的實體記憶體大小,單位kb
s    DATA    可執行程式碼以外的部分(資料段+棧)佔用的實體記憶體大小,單位kb
t    SHR     共享記憶體大小,單位kb
u    nFLT    頁面錯誤次數
v    nDRT    最後一次寫入到現在,被修改過的頁面數。
w    S       程序狀態(D=不可中斷的睡眠狀態,R=執行,S=睡眠,T=跟蹤/停止,Z=殭屍程序)
x    COMMAND 命令名/命令列
y    WCHAN   若該程序在睡眠,則顯示睡眠中的系統函式名
z    Flags   任務標誌,參考 sched.h
查詢登入當前系統的使用者資訊:w命令
[email protected]:~$ w
 20:15:44 up 11:17,  3 users,  load average: 0.21, 0.16, 0.16
USER     TTY      FROM             [email protected]   IDLE   JCPU   PCPU WHAT
ubuntu   :0       :0               Thu00   ?xdm?  30:09   1.63s /sbin/upstart --user
ubuntu   pts/7    :0               Thu23   45:01m 42:57   8.80s /home/ubuntu/inno/idea-IU-162.2032.8/bin/fsnotifier64
ubuntu   pts/18   :0               06:47    0.00s  0.47s  0.05s w

可查詢登入當前系統的使用者資訊,以及這些使用者目前正在做什麼操作

iostat

執行時,如果出現下面的提示資訊

[email protected]:~$ iostat
The 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
[email protected]:~$ free -m
             total       used       free     shared    buffers     cached
Mem:          1992        672       1320          6         22        209
-/+ buffers/cache:        440       1552
Swap:         3068        403       2665

free: 檢視系統記憶體的使用情況,-m引數表示按照兆位元組展示。 
最後兩列分別表示用於IO快取的記憶體數,和用於檔案系統頁快取的記憶體數。需要注意的是,第二行-/+ buffers/cache,看上去快取佔用了大量記憶體空間。這是Linux系統的記憶體使用策略,儘可能的利用記憶體,如果應用程式需要記憶體,這部分記憶體會立即被回收並分配給應用程式。因此,這部分記憶體一般也被當成是可用記憶體。如果可用記憶體非常少,系統可能會動用交換區(如果配置了的話),這樣會增加IO開銷(可以在iostat命令中提現),降低系統性能。

檢視CPU的佔用情況 mpstat

顯示每個CPU的佔用情況,如果有一個CPU佔用率特別高,那麼有可能是一個單執行緒應用程式引起的。

[email protected]:~$ mpstat -P ALL 1
Linux 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   %idle
10:57:31 PM  all    1.52    0.00    0.51    0.00    0.00    0.51    0.00    0.00    0.00   97.47
10:57:31 PM    0    3.03    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   96.97
10:57:31 PM    1    0.00    0.00    0.00    0.00    0.00    1.02    0.00    0.00    0.00   98.98

前端

由於我不是做前端的工作,所以沒有太多的經驗總結。不過程式碼方面效能優化有些是可以運用到前端。同事也可以減少前端的請求連結等等手段去優化。這裡由於本人不瞭解,不做過多的闡述。

讀書感悟

來自托馬斯·哈代《德伯家的苔絲》

  • 凡是有鳥歌唱的地方,也都有毒蛇嘶嘶地叫。
  • 越是有智慧的人,越能發現別人的本色。
  • 但是事情既已無可奈何,他就轉身彎腰,急忙往前趕路,不再去想這件事了。

經典故事

  
【抉擇】 
一個農民從洪水中救起了他的妻子,他的孩子卻被淹死了。事後,人們議論紛紛。有的說他做得對,因為孩子可以再生一個,妻子卻不能死而復活;有的說他做錯了,因為妻子可以另娶一個,孩子卻不能死而復活。我聽了人們的議論,也感到疑惑難決:如果只能救活一人,究竟應該救妻子呢,還是救孩子?於是我去拜訪那個農民,問他當時是怎麼想的。他答道:“我什麼也沒想。洪水襲來,妻子在我身過,我抓住她就往附近的山坡遊。當我返回時,孩子已經被洪水沖走了”。歸途上,我琢磨著農民的話,對自己說:所謂人生的抉擇不少便是如此


相關推薦

程式效能優化包括資料庫優化伺服器優化

開心一笑 世界上最互相信任的兩個人應該是初中老師和高中老師了。 初中老師:這個知識點到高中你們老師會講的,你們現在不必要知道。 高中老師:這個知識點你們初中老師肯定講過了,我就不講了。 我:你TM在逗我嗎??? 提出問題 效能優化時候,應該從哪幾方面入手???

iOS NSMutableAttributedString 實現富文字不同顏色字型下劃線

//    1> NSFontAttributeName(字型) //    該屬性所對應的值是一個 UIFont 物件。該屬性用於改變一段文字的字型。如果不指定該屬性,則預設為12-point Helvetica(Neue)。 //     //    2> NSParagraphSt

使用NSMutableAttributedString 實現富文字不同顏色字型下劃線

開發中,常常會有一段文字顯示不同的顏色和字型,或者給某幾個文字加刪除線或下劃線的需求。NSMuttableAttstring(帶屬性的字串),上面的一些需求都可以很簡便的實現。 1.例項化方法有兩種: 使用字串來初始化 ①:- (id)initWithSt

iOS APP內彈窗推送版本更新資訊實現跳轉強制更新

1、一開啟APP就檢測版本更新資訊,則需要在AppDelegate.mm裡面新增: NSString *version = [[[NSBundle mainBundle]infoDictionary] objectForKey:@"CFBundleVersion"]

WPF圖片瀏覽器顯示大圖小圖

1.概述                最近利用WPF做了一個圖片瀏覽器,能夠將資料夾中的所有圖片以小圖的形式顯示,並將選中的圖片以512*512大小顯示。顯示大圖當然用的是WPF自帶的Image控制元件,而顯示小圖則需要將所有的圖片放入ListBox控制元件中,ListB

vue專案效能優化路由懶載入gzip加速cdn加速

前端工程效能優化一說意義深遠悠長,本章主要介紹除了一些基礎優化外如何實行路由懶載入、Gzip加速、CDN加速,讓網頁飛的快一些。 基礎優化 老生常談的一些: 不要在模板中寫複雜的表示式 慎用watch尤其是deep 合理的使用v-if/v-show/v-for 善用keep-alive

JDBC資料庫的驅動連線java程式操作資料庫事務隔離級別連線池

java操作資料庫的思想:連上資料庫,傳送sql語句。在連上資料庫之前,要先用程式啟動資料庫,因此,可以通過反射載入類驅動(com.jdbc.mysql.Driver)。通過驅動管理類的靜態方法傳遞資料庫的url來獲取一個連線物件(connection)。有三個過載的方法,第一個user和p

懲罰函式法內點法外點法求解約束優化問題最優值 matlab

1、 用外點法求下列問題的最優解 方法一:外點牛頓法: clc m=zeros(1,50);a=zeros(1,50);b=zeros(1,50);f0=zeros(1,50);%a b為最優點座標,f0為最優點函式值,f1 f2最優點梯度。 syms x1 x2 e;  &n

神經網路優化演算法二正則化滑動平均模型

1、神經網路進一步優化——過擬合與正則化 過擬合,指的是當一個模型過為複雜後,它可以很好的“記憶”每一個訓練資料中隨機噪音的部分而忘了要去“學習”訓練資料中通用的趨勢。舉一個極端的例子,如果一個模型中的引數比訓練資料的總數還多,那麼只要訓練資料不衝突,這個模型完全可以記住所有訓練資料

人臉資料庫大全包括人臉識別關鍵點檢測表情識別,人臉姿態等等

搞計算機視覺的人,對人臉技術並不陌生。在做實驗的時候需要各種資料集進行訓練,卻往往苦於找不到合適的資料集,這篇文章將給大家帶來一點福音。目前為止最全的是人臉資料庫總結:The FERET program set out to establish a large databas

pfsense中文版下載包括。2.032.252.322.332.34

pfsense 中文版為方便各位網友,本人制作了包括pfsense2.03-pfsense2.34各版本的中文版,提供百度網盤下載。下載地址:鏈接:https://pan.baidu.com/s/1mix6AgC 密碼:9zqy安裝方法:方法一、在win PE系統的dos下用physdiskwrite工具寫盤

01 背包基礎 - 空間優化 滾動數組,一維陣列

pac 使用 dp2 -1 col date for png logs 2017-09-03 11:39:16 writer:pprp 以很簡單的一個動態規劃問題為引入: 從左上角到右下角走過的路徑和最大,問你最大為多少? 1、可以想到普通的dp 狀態轉移為: dp[i][

獲取碼值各種類型字符的ASCII和進制轉換系統包括正負數小數

獲取碼值 進制轉換 十進制小數負數轉二進制 java進制轉換 ASCII 獲取碼值和進制轉換程序由來: 本人發現計算機中的計算器木有將十進制小數轉二進制的功能,後來發現一些網站將十進制負數轉二進制只是求出整數的二進制,然後前面加“-”,這種表示不是真正的負數二進制。於是愛較真兒

獲取碼值和進制轉換系統包括正負數小數

獲取碼值 進制轉換 十進制小數負數轉二進制 java進制轉換 ASCII 獲取碼值和進制轉換程序由來: 本人發現計算機中的計算器木有將十進制小數轉二進制的功能,後來發現一些網站將十進制負數轉二進制只是求出整數的二進制,然後前面加“-”,這種表示不是真正的負數二進制。於是愛較真兒

Django的celery配置包括定時任務隊列

如何 one tab 輸入 ats minute 依然 threading att 一、安裝celery Django項目不需要安裝celery這個包,可以直接使用django-celery這個包,,先來安裝它,在終端中輸入: pip install django-cele

除錯經驗——建立個人的知識庫資料表資料庫部落格微博的意義

大學四年,記住的老師的話並不多,但有一句至今難忘。 那是大三電子電路實驗課中有一節的內容是組裝一臺收音機,那位試驗老師對我們說“你們一定要注意儲存好自己的學習成果,不斷積累,這個非常重要!”。 所以,畢業十幾年以來,別的東西沒有積累多少,各種資料倒是積累了不少,至於有多少價值,那是另一回

Spring學習第一章第二節:依賴注入包括自動裝配,物件的注入

依賴注入 前言 Spring Bean 定義繼承 Bean 定義模板 正文 Spring依賴注入 基於構造器的依賴注入 基於Setter方法的依賴注入 自

基於Taro + Dva構建的適配不同端微信小程式H5React-Native 的時裝衣櫥

前言 Taro 是一套遵循 React 語法規範的 多端開發 解決方案。現如今市面上端的形態多種多樣,Web、React-Native、微信小程式等各種端大行其道,當業務要求同時在不同的端都要求有所表現的時候,針對不同的端去編寫多套程式碼的成本顯然非常高,這時候只編寫一套程式碼就能夠適配到多端的能力就顯得極

中秋福利 | 10本技術圖書程式語言資料分析免費送

中秋將至,技術宅們有福利了,網易雲社群聯合博文視點為大家送來一大波技術圖書,內容涉及Kubernetes、Go語言、OpenResty、Python程式設計、Spark SQL、PyTorch等,話不多說,“十仁”乾貨陪你過中秋。參與規則:在知乎帖子評論回覆以下你最想看的一本

最短路演算法優化dijkstra演算法+鄰接表+佇列優化,bellman演算法+鄰接表+佇列優化

dijkstra演算法+鄰接表+佇列優化: #include<bits/stdc++.h> using namespace std; const int M=1000000000;