服務端調優與JVM調優


一、安裝Jmeter

  下載地址:http://jmeter.apache.org/download_jmeter.cgi

  下載后直接進入bin目錄,直接運行jmeter即可,我這里用得是mac,直接sh jmeter

  1、調整語言

    Options--Choose Languages--Chinese(Simple lified)

  2、添加jmeter-plugin插件

    下載地址:鏈接: https://pan.baidu.com/s/1RXD6JnT5LJx5mBvxmUf7JQ 提取碼: 90ni

    下載后文件為plugins-manager.jar格式,將其放入jmeter安裝目錄下的lib/ext目錄,然后重啟jmeter,即可。

  3、添加jpgc插件

    這個插件可以監測TPS,RT等重要指標。

    選項-plugin Manager --jpgc - Standard Set,安裝后重啟。

二、壓測

  寫一個簡單的demo

    @RequestMapping(value = "/goods/detail/nocache/{seckillId}",method = RequestMethod.GET)
    public TbSeckillGoods findOneNoCache(@PathVariable Integer seckillId){
        TbSeckillGoods  seckillGoods = seckillGoodsMapper.selectByPrimaryKey(id);
    }

  運行:

nohup java -jar jshop.jar --spring.config.addition-location=application.yaml > shop.log 2>&1 &

 

  這就是一個最簡單的使用主鍵查詢。

   1、添加測試項(01-秒殺系統測試方案)

    測試方案--添加--線程(用戶)--線程組,設置測試接口名稱(01-商品詳情測試方案)。

    測試接口--添加--取樣器--HTTP請求(01-商品詳情HTTP請求)

    測試接口--添加--監聽器--聚合報告(02-商品詳情聚合報告)

    測試接口--添加--監聽器--查看結果樹(03-商品詳情結果樹)

    測試接口--添加--監聽器--jp@gc - Transactions per Second (04-商品詳情接口TPS)

    測試接口--添加--監聽器--jp@gc - Response Times Over Time(05-商品詳情響應時間)

      

 

  2、驗證

    點擊開始,然后查看結果樹中的響應數據,可以看到正常返回,驗證無誤。

      

 

   3、正式壓測

    修改測試方案中的線程數和循環次數,這里模擬20W個樣本,線程數為4000,啟動時間為5秒,循環次數為50次,這幾個參數的意思是:在5秒內順序啟動4000個線程,這個操作循環50次。這50次循環是並行執行的。

    (1)TPS

      

 

     如果服務的TPS存在明顯的抖動,說明要么服務有問題,要么網絡有問題。TPS性能曲線不能出現明顯抖動(當前條件當測試演變比較穩定),查看服務問題。

     這里再說明一下TPS和QPS,TPS ,QPS,吞吐量:大多數情況下,單獨一個接口: TPS = QPS = 吞吐量(每秒請求數)

      

 

    (2)RT

      

 

     (3)聚合報告

      

 

       # 樣本: 測試的樣本數 20w

      # 平均值: 所有的請求從發送請求到請求結束所消耗的平均時間

      # 中位數:50%的請求在713ms之內響應結束

      # 90%百分位:90%的請求在782ms之內響應結束

      最小值: 請求消耗的最小時間

    (4)測試參數

      

 

三、服務端調優

  1、分析與調優

  查看線程數:pstree -p 進程號 | wc -l

pstree -p 3769 | wc -l

 

  如果沒有命令,需要安裝pstree:

yum -y install psmisc 

 

      

 

  經過測試,發現服務器只產生了 200 個線程來處理業務請求,增加線程數,可以提升吞吐能力;考慮 cpu 處理能力的問題,cpu 上下文切換耗時,搶占 cpu 等待問題;考慮 cpu 性能損耗問題,使用 top 查看即可;

  Springboot內置的Tomcat配置信息在:spring-boot-autoconfigure-2.2.5.RELEASE.jar中的spring-configuration-metadata.json中

      

  

  其中比較重要的三個配置項:最大連接數、服務隊列、最大線程數,三者的關系如下圖所示:

    首先使用等待隊列接收請求,然后創建連接,然后執行業務,如果當最大連接數,等待隊列都已經滿了,tomcat 服務就會拒絕連接。

      

   (1)最大連接數:

      

 

   (2)服務隊列

      

 

   (3)最大線程數

      

 

   由於部署應用的服務器是4C8G,單個線程默認為200個線程,這里4個CPU,將線程數調整為800。

server:
  port: 9000
  tomcat:
    # 編碼格式
    uri-encoding: utf-8
    # 服務隊列
    accept-count: 1000
    # 最大連接數
    max-connections: 20000
    # 最大線程數
    max-threads: 800
    # 初始化線程,應對突發流量
    min-spare-threads: 10

 

  2、驗證壓測

      

 

   經過 20w 個樣本的測試,發現 TPS 沒有發生任何的變化,TPS = 2700

      

 

   可以發現在服務器最大線程數增加了 4 倍,理論上來說,TPS 一定會增加 4 倍,但是根據實際測試結果,發現 TPS 沒有任何的變化,這是因為沒有執行任何業務,不是一個耗時的操作,主鍵查詢:0-10ms 結束,無需要對一個不耗時操作進行調優。

  結論:調優應該是對於耗時操作進行調優。

  3、模擬耗時操作調優

  模擬一個耗時操作

      public TbSeckillGoods findOne(Integer id){
            //直接從數據庫查詢
            //主鍵查詢 : cpu不耗時操作
            TbSeckillGoods  seckillGoods = seckillGoodsMapper.selectByPrimaryKey(id);
            //計算對象大小
            //模擬程序耗時操作,如果方法是一個筆記耗時的操作,性能優化非常有必要的!!
              try {
                  Thread.sleep(1000);
                  LOGGER.info("模擬耗時操作,睡眠1s時間!");
                  LOGGER.info("對象占用jvm堆內存大小: {}", RamUsageEstimator.humanSizeOf(seckillGoods));
            } catch (InterruptedException e) {
                  e.printStackTrace();
            }
            //返回結果
            return seckillGoods;
      }

 

   在未調優的情況下進行壓測:沒有優化之前,對於一個耗時操作來說,TPS = 200

      

 

  調優后壓測:調優之后的 TPS 情況(線程數增加:800) -- 理論上: cpu 沒有任何壓力,TPS 應該會獲得倍數的提升,提升 4 倍

      

 

   經過測試:發現 TPS 有了 4 倍的提升,tps = 800

  4、Keepalive

  客戶端和服務端連接的時候,為了防止頻繁建立連接,釋放連接,浪費資源,這樣就好損耗的性能,造成性能嚴重下降;

       

   可以發現: jmeter connection : keep -alive 長連接

      

 

     查看連接數:

netstat -anp | grep ESTABLISHED | wc -l

  

   但是keepalive 長連接本身也會消耗大量資源,如果這些長連接不能及時釋放,長連接將會占用大量資源,系統 TPS 就會上不去;因此對 keepalive 設置一個比較合理的連接數;另外: 長連接也必須及時釋放,沒有請求使用這個鏈接,這個鏈接一段時間必須釋放;

  可以在代碼中定制tomcat服務器的長鏈接設置。

@Component
public class WebServerConfig implements WebServerFactoryCustomizer<ConfigurableWebServerFactory>{
    // 定制tomcat服務器
    @Override
    public void customize(ConfigurableWebServerFactory configurableWebServerFactory) {
        ((TomcatServletWebServerFactory)configurableWebServerFactory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
            // 獲取tomcat連接器
            @Override
            public void customize(Connector connector) {
                // 獲取protocol
                Http11NioProtocol protocolHandler = (Http11NioProtocol) connector.getProtocolHandler();
                // 如果keepalive連接30s,還沒有人使用,釋放此鏈接
                protocolHandler.setKeepAliveTimeout(30000);
                // 允許開啟最大長連接數量,4cpu,8gb
                protocolHandler.setMaxKeepAliveRequests(10000);
            }
        });
    }
}

 

 四、線上問題分析

(一)問題分類

  發現問題,解決問題 (測試時候發現一些問題,修復,調試,調優 , 更多的時候: 上線以后發現一些問題,解決問題)系統出現問題分類:

  1、系統異常

    CPU 占用率過高,磁盤滿了,磁盤 IO 阻塞,網絡流量異常等等問題

    排查指令:TOP,free,dstat , pstack , vmstat , strace 獲取異常信息,排查系統異常

  2、業務異常

    流量太大系統扛不住,耗時長,線程死鎖,並發問題,頻繁 full gc ,oom 等等

    排查: top, jstack ,pstack , strack 日志

(二)問題排查

  1、TOP命令

    Top 指令監控 cpu 使用情況,根據 cpu 使用分析系統整體運行情況

      

 

     關注性能指標: load average : 1 分鍾之內 cpu 平均使用率,5 分鍾之內 cpu 平均使用率,15分鍾之內 cpu 平均使用率;如果1分鍾之內cpu使用率較高,但是5分鍾或15分鍾內較低,有可能是短暫的流量激增導致,可以暫時不用關心。

    單核心 cpu:

      1)load average < 1 , 表示 cpu 毫無壓力,比較空閑,運行流暢

      2)load average = 1 , 表示 cpu 剛剛被占滿,沒有可供提供的 cpu 資源

      3)load average > 1 , 表示 cpu 已經滿負荷運作,線程處於阻塞等待狀態,等待 cpu資源

      4)load average > 5 , 表示 cpu 已經處於超負荷運作,線程已經大面積阻塞,必須進行優化處理;

    4 核心 cpu:

      1)load average < 4 , 表示 cpu 毫無壓力,比較空閑,運行流暢

      2)load average = 4 , 表示 cpu 剛剛被占滿,沒有可供提供的 cpu 資源

      3)load average > 4 , 表示 cpu 已經滿負荷運作,線程處於阻塞等待狀態,等待 cpu資源

      4)load average > 10 , 表示 cpu 已經處於超負荷運作,線程已經大面積阻塞,必須進行優化處理;

  2、Free命令

    Free 排查線程問題:內存問題很多時候引起 cpu 較高的原因。

      

 

  3、磁盤

    Df 指令查看磁盤問題,查看磁盤使用情況,有時候服務出現問題,其實就是磁盤出現問題。

      

 

  4、網絡

    Dstat 命令: 集成 vmstat , iostat , netstat ,工具完成任務,-c 查看 cpu 使用情況, -d 查看磁盤讀寫,-n 網絡狀態 -l 顯示系統負載

    詳細的參數展示可以參考下這篇文章:http://www.yishimei.cn/network/850.html

      

 

 五、JVM調優概述

(一)為什么調優

  1、調優的目的

    調優的目的就是為了提升項目性能,避免項目出現一些不可預知的 bug(頻繁 fullgc,oom);

    (1)jvm 堆內存空間對象太多(Java 線程,垃圾對象),導致內存空間被占滿,程序跑不動 –性能嚴重下降,通過調優:及時釋放內存空間

    (2)垃圾回收線程太多(頻繁的垃圾回收,垃圾回收線程也會占用 CPU,內存資源),必然導致程序性能下降,通過調優:防止頻繁的 gc

    (3)垃圾回收導致 STW (stop the world : 停止整個世界 --- 整個業務執行全部暫停),通過調優:盡可能減少 gc 次數

      

  2、JVM 調優的本質

    jvm 調優本質就是(對內存空間的調優)及時是否垃圾對象占用的內存空間,讓程序性能得以提升,讓其他業務線程可以使用內存空間;

  3、如果把 jvm 堆內存設置的足夠大(無限大),是不是不需要垃圾回收?

    理論上確實可以考慮內存空間垂直擴容,解決 JVM 內存問題,但是同樣存在問題:

      (1)成本問題 --- 高性能服務器

      (2)一旦觸發垃圾回收 --- gc 時間比較長

      (3)微服務架構場景下(每一個服務都是一個微小,獨立的服務) --- 水平擴展

      (4)尋址能力的問題(JVM 默認內存調優分配空間: 32GB,超過32G就不會進行調優):

          32 位操作系統: 2~32 = 4GB 內存空間 --- Java 對象 8 字節 指針壓縮 : 4GB *8 = 32GB

          64 位操作系統 2~64 = 16384PB

    小結: JVM 內存空間設置,必須設置一個大小合適的內存空間,不能太大,也不能設置太小;

      (1)成本問題 --- 高性能服務器

      (2)一旦觸發垃圾回收 --- gc 時間比較長

      (3)微服務架構場景下(每一個服務都是一個微小,獨立的服務) --- 水平擴展

(二)JVM 調優原則

  1、gc 時間足夠小(堆內存設置足夠小)

    此原則就是讓我們在設置堆內存空間時候,不要把內存空間設置的太多,防止 gc 消耗太多的時間;

  2、gc 的次數足夠少(堆內存空間設置的足夠大)

    GC 觸發條件: 內存空間被占滿,立即觸發垃圾回收(ps,po),也就是說內存空間被占滿一次,就發生一次 gc,占滿多次就發生多次 gc;

  3、發生 fullgc 周期足夠長(最好不要發生 fullgc)

    (1)metaspace 元數據空間大小設置合適 ,metaspace 一旦發生擴容,fullgc 就會發生

    (2)老年代空間設置一個合理的大小,防止 fullgc

    (3)盡量讓垃圾對象在年輕代回收(90%)

    (4)盡量防止大對象的產生,一旦大對象多了以后,就可能發生 fullgc , 甚至 OOM

(三)JVM 調優原理

  1、JVM 調優本質:

     回收垃圾,及時釋放內存空間。在 Java 堆內存中,那些沒有被引用的對象就是垃圾(高並發模式下,大量的請求在內存空間中創建了大量的對象,這些對象不會主動消失,必須進行垃圾回收,當然 Java 語言自己提供了垃圾回收器,幫助我們回收垃圾,JVM 垃圾是自動進回收的)

    JVM 提供 2 種方法尋找垃圾:引用計數法和根可達算法

  2、垃圾清理算法:

    mark-sweep 標記清除算法、copying 拷貝算法、mark-compact 標記壓縮算法。

    標記清除算法:

      過程:(1)使用根可達算法找到垃圾對象,對垃圾對象進行標記(僅僅是做一個標記);(2)對標記的對象做清除。

      優點: 簡單,高效;

      缺點: 產生很多的內存碎片

    copying 算法 – 一開始把內存空間一分為二,分為 2 份大小相同的內存空間,一般內存空間作為備份使用。

      過程:(1)選擇(尋址)存活對象;(2)把存活對象拷貝另一半空閑空間中,且是連續的空間;(3)把存活對象拷貝結束后,另一半空間中就是垃圾對象(全是垃圾對象),直接清除即可;

      優點:簡單,內存空間是連續的,不會存在內存碎片

      缺點:內存空間的浪費

    mark-compact 標記壓縮算法:

      過程:(1)標記垃圾(只標記,不清除);(2)再次掃描內存空間(未被標記的對象就是存活對象),找到存活對象,且把存活對象向一端移動(一端內存空間是連續的)--壓縮,整理;(3)當存活對象全部被移動到一端后,另一端就是垃圾對象,直接清除即可

  3、垃圾回收器

    Java 語言提供了 10 種垃圾回收器:

      

 

   特點:

    (1)Serial(年輕代) Serial Old(老年代) , parNew(年輕代) CMS(老年代) , Parallel Scavenge(年輕代) Parallel Old(老年代) 都屬於物理分代模型中垃圾回收器,年輕代,老年代模型,分別都使用不同的垃圾回收器;

    (2)G1 在邏輯上分代模型,使用非常方便;關於年輕代,老年代只需要使用 g1 一個垃圾回收器即可;

    (3)zgc zgc 是 jdk11 新加入的垃圾回收器,在試驗階段;

    (4)shenandoah openJDK 的垃圾回收器

    (5)epsilon 是 debug 使用的,在調試環境下,驗證 jvm 內存參數設置的可行性;

    (6)Serial 和 Serial Old 串行化的垃圾回收器

    (7)parNew和CMS : 響應時間優先垃圾回收器組合 (fullgc 比較多,無法避免 --- cms)

    (8)parallel scavenge 和 parallel old : 吞吐量優先的垃圾回收器組合

  常用垃圾回收器組合:

    (1)Serail + Serial Old : 串行化的垃圾回收器,適合單核心的 cpu 服務器

    (2)parNew + CMS : 響應時間有些的垃圾回收器,並行,並發垃圾

    (3)Parallel Scavenge+Parallel Old : 並行垃圾回收器

    (4)g1 邏輯上分代垃圾回收器

  4、垃圾回收器原理

  (1)Serial+Serial Old

    Serial : 年輕代垃圾回收器,單線程垃圾回收器; Serial Old : 老年代的垃圾回收器,也是一個單線程的垃圾回收器,適合單核心 cpu 情況。

      

 

     注意:1、stw : 任何垃圾回收器都無法避免 stw(stop the world : 當進行 gc 的時候,整個業務線程必須暫停),如果 stw 時間過長,或者 stw 發生次數過多,都會影響程序的性能;2、垃圾回收線程: 多線程,單線程,並發,並行

  (2)Parallel Scavenge + Parallel Old

    Parallel Scavenge+Parallel Old : 並行垃圾回收器,吞吐量優先的垃圾回收器組合,是 JDK8 默認垃圾回收器組合;(並行: 同一個時候,同時執行,並行;並發: 在一段時間內,多個線程搶占式交叉執行,叫做並發模式;)

    PS + PO : 垃圾回收器進行垃圾回收器的時候,采用多線程模式回收垃圾

      

 

   (3)parNew+CMS

    parNew : 年輕代垃圾回收器,並行的垃圾回收器;

      

 

     CMS : 並發垃圾回收器,響應時間優先垃圾回收器

      

 

         初始化標記:(尋址垃圾比較耗時)只標記跟根對象相關聯的對象,因此耗時比較少,且采用單線程模式標記

        並發標記: (尋址垃圾比較耗時)為了防止 gc 時候 stw, 因此使用並發模式標記垃圾,也就是說讓業務線程和 gc 標記線程交叉執行;

        重新標記: 重新標記漏標的對象,此時漏標對象比較少,因此耗時比較少

        並發清理:(清理垃圾比較耗時) 采用並發模式清理垃圾,業務線程和清理垃圾線程交叉執行,以此減少業務線程停頓的時間;

  (4)G1

    G1 jdk11 成為了默認的垃圾回收器;采用了分區的思想;對內存進行邏輯上分代;采用RememberSet 集合記錄每一個 region 區域

  5、內存分代模型

      

 

  通過內存分代模型: 大多數對象都會在年輕代被回收(90%+),超過 15 次沒有被回收的對象就進入 old 區域。垃圾回收器觸發時機:

    (1)ps + po : 當內存空間(eden,old)被占滿后,觸發垃圾回收器

    (2)cms 垃圾回收器

        jdk1.5 : 68% ,當 eden 區域被裝載到 68%的時候,觸發垃圾回收器

        jdk1.6+ : 92% 觸發垃圾回收器

六、JVM調優實戰

(一)調優實戰

  JVM 調優的本質就是 GC(垃圾回收,及時釋放掉內存,提供給其他的線程使用—並發模式),每次 GC 的時候,導致業務線程 STW, 因此必須進行綜合的考量:頻繁的 gc 也會導致性能下降

  JVM 調優其實就是選擇一個合適的垃圾回收器(在不同的場景下),設置一些合理垃圾回收參數(參考 JVM 內存模型),分配合理的內存(gc 時間少,次數少,jvm 內存既不能太大,也不能太小)。因此調優的實踐本質就是設置 jvm 參數

  1、典型設置

  典型的參數設置: 服務器配置 —> 4cpus,8GB

    1、-Xmx4000m 設置 JVM 堆內存最大值(經驗值設置:3500m --- 4000m,內存大小的設置,沒有一個固定值,根據業務場景實際情況,根據壓力測試運行情況進行調試,在上線后,進行調試)。例如: 對象 1 占用內存 128KB;對象 2 占用內存 300KB

    2、-Xms4000m 設置 JVM 初始化內存(必須和 Xmx 最大內存設置一致,防止內存抖動,損耗性能)

    3、-Xmn2g 設置年輕代大小(eden ,s0 ,s1)

    4、-Xss256k 設置線程堆棧大小,jdk1.5+版本線程堆棧默認 1MB, 相同內存情況下,線程堆棧越小,操作系統有能力創建更多線程,系統性能將會越好;

  查看對象占用JVM堆內存大小:

RamUsageEstimator.humanSizeOf(seckillGoods)

 

  然后調整代碼的執行命令,設置上面的參數:

nohup java -Xmx4000m -Xms4000m -Xmn2g -Xss256k -jar jshop.jar --spring.config.addition-location=application.yaml > shop.log 2>&1 &

      

 

 

   根據壓力測試結果(20w 樣本),發現 JVM 內存參數設置后,沒有任何優化效果(變化),原因就在於在這個業務場景下沒有發生頻繁的 gc(gc 導致 stw ,stw 最終影響性能);那我們是根據什么指標判斷 jvm 調優的參數是合適的,是否能提到調優的效果的呢:

    (1)發生幾次 GC ,GC 次數是否減少,是否頻繁的發生 GC, 發送 GC 時間

    (2)業務線程執行時間比例 (業務線程執行時間超過 95%, 5%時間 gc 時間,此時不需要調優)

    (3)是否發生 fullgc (fullgc 耗時比較長,性能影響比較大,fullgc 發生次數)

    (4)oom

   2、GC日志

    JVM 在 gc 的時候輸出日志,把日志寫入文件中,使用相應工具(gceasy.io)對日志進行分析,分析 jvm 堆內存調優的結果是否合適。

nohup java -Xmx4000m -Xms4000m -Xmn2g -Xss256k -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log -jar jshop.jar --spring.config.addition-location=application.yaml > shop.log 2>&1 &

 

     通過 jvm 相關參數,輸出 gc 日志,通過分析 gc 日志判定 gc 的參數設置是否合理;從而給調試 jvm 堆內存設置提供參考依據;

    拿到 gc 日志后,可以在  gceasy.io  網站進行在線分析

    (1)內存使用情況

        用於展示各分代的總內存和最大使用內存。

      

 

 

     (2)執行時間對比

      這個是關鍵的是否需要JVM調優的判斷標准,如果業務時間占比大於95%,就無需調優。

      

   

     (3)GC耗時占比

      

 

     (4)發生GC的時間點和次數

        根據內存分布情況,old 最大使用 157mb , 而在此時卻發生了 fullgc ,很明顯這是不正常的,必須進行調試,規避不正常的 fullgc

      

 

     (5)GC統計

      

 

   3、fullGC問題

    20w 樣本測試后,old 區域使用最大值 157mb, old 區域分配的內存是 1.9gb , 卻發生了 full gc,這肯定不正常的,原因: metaspaceSize 雲數據空間發生了擴展,導致了 fullgc 的發發生;metaspace 發生一次擴容,就會發生一次 fullgc(可以查看gc日志,可以看到元空間占用內存在變大)

jstat -gcutil 11811
jstat -gc 11811 2s 3
java -XX:+PrintFlagsFinal -version | grep MetaspaceSize

 

      

 

     根據 metaspace 擴容閥值的大小,看出超過 20m,就會發生第一次擴容(gc日志);

       

 

     Metaspace 發生了擴容(gc日志):

      

 

     解決方案: 觀察 gc 日志,看 metaspace 最大使用空間是多少,然后把 metaspace 空間大小設置為比這個值大即可;

        

 

     根 據 上 圖 所 示 , metaspace>55.11mb ; metaspace = 256m , 完 全 夠 用 的 ;-XX:MaxMetaspaceSize=500m :定義最大的元數據空間,此時如果 metaspace 裝不下,就會發生 fullgc ,同時 oom;

nohup java -Xmx4000m -Xms4000m -Xmn2g -Xss256k -XX:MetaspaceSize=256m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log -jar jshop.jar --spring.config.addition-location=application.yaml > shop.log 2>&1 &

 

     查看日志優化情況,看 fullgc 是否發生:

       

 

     可以發現此時 fullgc 消失了,說明解決問題:

      

 

   4、Yong&old

     年輕代,老年代大小比例的設置根據業務情況進行靈活的設置,無非就是 yong 空間設置大些,盡量讓對象在年輕被回收;或者是老年代設置大些,在一些大對象,老年代對象比較多的情況下;

    設置方案: -XX:NewRatio = 4 ,年輕代 : 老年代比值 = 1:4,預測結果: 年輕代空間進一步縮小(更頻繁的 yong gc – 耗時少),老年代的空間進一步增大(盡量防止 fullgc 的發生 – 不耗時)

    分配結果: 1、yong : old = 1:4 (4000MB) 800MB:3200MB , yong memory 變得更小了,oldmemory 變得更大了;2、-Xmn2g 直接設置年輕代大小,剩下的就是老年代的;

    修改配置:將Xmn刪除(-Xmn2g),新增NewRatio配置項(-XX:NewRatio=4)

nohup java -Xmx4000m -Xms4000m -XX:NewRatio=4 -Xss256k -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log -jar jshop.jar --spring.config.addition-location=application.yaml > shop.log 2>&1 &

 

       

 

     Yong gc 發生的次數更多了,但是 gc 時間更加快速了,但是總消耗的時間變多了;

    但是這種也不是不能這樣設置,這是一個需要權衡的結果,使用場景: 防止發生 fullgc(fullgc 有一些,消耗時間)

      

 

   5、Eden & s0 & s1

    盡量讓對象在年輕代被回收(大多數對象都在年輕代被釋放內存)官方推薦設置: eden : s0 : s1 = 8:1:1 設置方式: -XX:SurvivorRatio = 8。

 (二)垃圾回收器組合

  1、吞吐量優先

    並行垃圾回收器:

      年輕代: parNew , Parallel Scavenge

      老年代: Parallel old

    對於吞吐量優先的垃圾回收器: 使用常用組合: ps + po ,此組合是 jdk1.8 默認的垃圾回收器

nohup java -Xmx4000m -Xms4000m -Xmn2g -Xss256k -XX:MetaspaceSize=256m -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log -jar jshop.jar --spring.config.addition-location=application.yaml > shop.log 2>&1 &

 

  2、響應時間優先

    響應時間優先組合: parNew + CMS 垃圾回收器 ,響應時間優先主要是對 CMS(老年代垃圾回收器)來說的,適用於:老年代發生 fullgc 比較多的情況,且無法避免 fullgc;

    -XX:+UseParNewGC : 年輕代垃圾回收器,並行的垃圾回收器

    -XX:+UseConcMarkSweepGC: 老年代的垃圾回收器,並發的垃圾回收器(業務線程交叉執行)

nohup java -Xmx4000m -Xms4000m -Xmn2g -Xss256k -XX:MetaspaceSize=256m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log -jar jshop.jar --spring.config.addition-location=application.yaml > shop.log 2>&1 &

  3、G1 組合

  XX:+UseG1GC : 表示使用 g1 垃圾回收器; 使用更加簡單,邏輯上分代模型;

nohup java -Xmx4000m -Xms4000m -Xmn2g -Xss256k -XX:MetaspaceSize=256m -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log -jar jshop.jar --spring.config.addition-location=application.yaml > shop.log 2>&1 &

 

   可以發現: 垃圾回收次數比較少的,但是總耗時比較長;

       

 

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM