目錄
Kit
Apache JMeter
VisualVM
堆內存
jvm內存模型
垃圾回收(Garbage Collection, GC)
新對象分配內存
GC步驟
MinorGC
性能優化
影響因素
優化
nginx動靜分離
優化三級分類獲取
Jvm參數配置堆區
測試
Kit
Apache JMeter
壓力測試,模擬大量用戶并發訪問
VisualVM
監控、分析和調優 Java 應用程序的性能
VisualGC 插件:監控垃圾回收
堆內存
jvm內存模型
堆區:
所有對象實例和數組都存儲在堆區,堆區是線程共享的,所有線程都可以訪問堆中的對象。
堆區結構:
-
年輕代(Young Generation):
-
Eden 區:新創建的對象首先分配在這里。
-
Survivor 區:分為 From 和 To 區,存放經過一次 GC 后仍然存活的對象。
-
-
老年代(Old Generation):存放長期存活的對象。
-
元空間(Metaspace):存放類的元數據(如類定義、方法信息等)。
垃圾回收(Garbage Collection, GC)
新對象分配內存
- 新創建的對象首先分配在 Eden 區
- 當 Eden 區滿時,觸發 Minor GC
- MinorGC后,若Eden區放得下,則存入Eden區
- 若MinorGC后,Eden空間仍然不足,則為大對象,直接分配至Old區
- 若Old區空間不足,觸發FullGC,對整個堆內存進行垃圾回收。
GC步驟
(1) 標記(Marking)
-
遍歷所有對象,標記哪些對象是存活的(被引用的),哪些是垃圾(未被引用)。
-
從 GC Roots(如線程棧、靜態變量等)開始,遞歸標記所有可達對象。
(2) 清除(Sweeping)
-
清除未被標記的垃圾對象,釋放它們占用的內存空間。
-
清除后,內存可能會產生碎片。
(3) 壓縮(Compacting)
-
將存活的對象移動到內存的一端,整理出連續的內存空間,減少內存碎片。
-
這一步不是所有 GC 算法都會執行(如 CMS 就不壓縮)。
MinorGC
- 標記 Eden 區和 From 區(當前活動的 Survivor 區)中的存活對象。
- 將存活的對象復制到 To 區(另一個 Survivor 區)。
- 清空 Eden 區和 From 區,From和To角色互換
角色交換:
在下次 Minor GC 時,原來的?To 區?變為新的?From 區,而原來的?From 區?變為新的?To 區。
這種交換確保了每次 Minor GC 都有一個空的 Survivor 區用于存放存活對象。?
對象晉升:?
如果對象在 Survivor 區中經歷了多次 Minor GC(默認是 15 次,可以通過?
-XX:MaxTenuringThreshold
?參數調整),它會被晉升到?老年代。
?為什么需要兩個 Survivor 區?
減少內存碎片:通過復制算法,將存活對象從一個 Survivor 區復制到另一個 Survivor 區,可以整理內存,減少碎片。
提高垃圾回收效率:每次 Minor GC 只需要處理 Eden 區和其中一個 Survivor 區,而不是整個年輕代。
性能優化
影響因素
中間件
- client - > nginx - > 網關 - > server????????中間件越多,網絡IO交互越多,性能損耗越大
業務
- ?DB(MySQl優化)
- 模板渲染(開啟緩存)
- 靜態資源(動靜分離)
優化
1.日志:僅報錯
logging:level:com.elysia.gulimall.product: error
2. MySQL加索引
3.thtmeleaf 開啟ceche
4.nginx動靜分離
5.優化業務邏輯
6.通過 JVM 參數(如?-Xmx
?和?-Xms
)進行配置堆區
nginx動靜分離
將js,css,img等靜態資源存放在nginx中,靜態資源由nginx返回。
目錄:
nginx/html/static/index :css,js,img,json
請求靜態資源:
????????gulimall.com/static/index/js/catalogLoader.js
config:
upstream gulimall {server 192.168.40.1:88;
}server {listen 80;server_name gulimall.com;location /static/ {root /usr/share/nginx/html;}location / {proxy_set_header Host $host;proxy_pass http://gulimall;}#error_page 404 /404.html;# redirect server error pages to the static page /50x.html#error_page 500 502 503 504 /50x.html;location = /50x.html {root /usr/share/nginx/html;}}
優化三級分類獲取
原代碼13行和19行多次查詢數據庫,獲取子分類list
@Overridepublic List<CategoryEntity> getLevel1Category() {return this.list(new QueryWrapper<CategoryEntity>().eq("cat_level",1).eq("show_status",1));}@Overridepublic Map<String, List<Level2CategoryVo>> getLevel2AndLevel3Category() {//一級分類List<CategoryEntity> level1 = this.getLevel1Category();Map<String, List<Level2CategoryVo>> categoryMap = level1.stream().collect(Collectors.toMap(k -> k.getCatId().toString(),v ->{//查詢該一級分類下的二級分類List<CategoryEntity> level2List = this.list(new QueryWrapper<CategoryEntity>().eq("parent_cid", v.getCatId()));List<Level2CategoryVo> level2CategoryVos = null;if (level2List != null){level2CategoryVos = level2List.stream().map(level2 -> {//查詢 二級分類 下的 三級分類List<CategoryEntity> level3List = this.list(new QueryWrapper<CategoryEntity>().eq("parent_cid", level2.getCatId()));List<Level2CategoryVo.Level3Category> collect = null;if (level3List != null) {collect = level3List.stream().map(level3 -> {Level2CategoryVo.Level3Category level3Category = new Level2CategoryVo.Level3Category(level2.getCatId(), level3.getCatId(), level3.getName());return level3Category;}).collect(Collectors.toList());}Level2CategoryVo level2CategoryVo = new Level2CategoryVo(v.getCatId(), collect, level2.getCatId(), level2.getName());return level2CategoryVo;}).collect(Collectors.toList());}return level2CategoryVos;}));return categoryMap;}
獲取全部分類,通過filter獲取某分類的子分類list
@Overridepublic Map<String, List<Level2CategoryVo>> getLevel2AndLevel3Category() {List<CategoryEntity> selectList = this.baseMapper.selectList(null);//一級分類List<CategoryEntity> level1 = this.getByParentCid(selectList,0L);Map<String, List<Level2CategoryVo>> categoryMap = level1.stream().collect(Collectors.toMap(k -> k.getCatId().toString(),v ->{//查詢該一級分類下的二級分類List<CategoryEntity> level2List = getByParentCid(selectList,v.getCatId());List<Level2CategoryVo> level2CategoryVos = null;if (level2List != null){level2CategoryVos = level2List.stream().map(level2 -> {//查詢 二級分類 下的 三級分類List<CategoryEntity> level3List = getByParentCid(selectList,level2.getCatId());List<Level2CategoryVo.Level3Category> collect = null;if (level3List != null) {collect = level3List.stream().map(level3 -> {Level2CategoryVo.Level3Category level3Category = new Level2CategoryVo.Level3Category(level2.getCatId(), level3.getCatId(), level3.getName());return level3Category;}).collect(Collectors.toList());}Level2CategoryVo level2CategoryVo = new Level2CategoryVo(v.getCatId(), collect, level2.getCatId(), level2.getName());return level2CategoryVo;}).collect(Collectors.toList());}return level2CategoryVos;}));return categoryMap;}private List<CategoryEntity> getByParentCid(List<CategoryEntity> selectList,Long parentCid) {return selectList.stream().filter(categoryEntity -> {return categoryEntity.getParentCid().equals(parentCid); } ).collect(Collectors.toList());}
Jvm參數配置堆區
將堆區固定為1024m,Eden區 512m
測試
全鏈路測試,請求首頁
50線程數,吞吐量:1100/s