当前位置: 首页 > news >正文

谷粒商城:性能压测JVM堆区

目录

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)

    新对象分配内存

    1. 新创建的对象首先分配在 Eden 区
    2. 当 Eden 区满时,触发 Minor GC
    3. MinorGC后,若Eden区放得下,则存入Eden区
    4. 若MinorGC后,Eden空间仍然不足,则为大对象,直接分配至Old区
    5. 若Old区空间不足,触发FullGC,对整个堆内存进行垃圾回收。

    GC步骤

    (1) 标记(Marking)

    • 遍历所有对象,标记哪些对象是存活的(被引用的),哪些是垃圾(未被引用)。

    • 从 GC Roots(如线程栈、静态变量等)开始,递归标记所有可达对象。

    (2) 清除(Sweeping)

    • 清除未被标记的垃圾对象,释放它们占用的内存空间。

    • 清除后,内存可能会产生碎片。

    (3) 压缩(Compacting)

    • 将存活的对象移动到内存的一端,整理出连续的内存空间,减少内存碎片。

    • 这一步不是所有 GC 算法都会执行(如 CMS 就不压缩)。

    MinorGC

    1. 标记 Eden 区和 From 区(当前活动的 Survivor 区)中的存活对象。
    2. 将存活的对象复制到 To 区(另一个 Survivor 区)。
    3. 清空 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

        @Override
        public List<CategoryEntity> getLevel1Category() {
            return this.list(new QueryWrapper<CategoryEntity>().eq("cat_level",1).eq("show_status",1));
        }
     
        @Override
        public 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

        @Override
        public 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

    相关文章:

  • 前端学习笔记(三)——ant-design vue表单传递数据到父页面
  • 【从零开始学习计算机科学】数据库系统(十)XML、XPATH、XQuery与XML数据库
  • 在 Ubuntu 上安装和配置 Docker 的完整指南
  • 计算机网络-网络存储技术
  • Java随机数生成终极指南:数组存储到Math.random()与Random类的深度对比
  • 【金字塔原理】如何有效提升思考和表达能力
  • docker基本应用和相关指令
  • 6. JavaScript 数组方法
  • Nature最新报道:分析四大主流AI工具、性能测评、推荐使用场景
  • Vue3中slot(插槽)的作用
  • 【Pandas】pandas Series last_valid_index
  • 计算机网络——DHCP实验
  • 使用 Excel 实现绩效看板的自动化
  • chrome浏览器拓展插件捕获页面的响应体内容
  • 深度学习知识:softlabel策略
  • chrome浏览器插件拓展捕获页面的响应体内容
  • AI+办公 Task2
  • Nacos入门实战(二)配置中心及配置实战
  • 在shell中分割文件
  • Python-树状数组算法入门
  • 悠悠我心的个人网站素材/搜资源
  • 特效视频网站/营销型企业网站的功能
  • 公司网络建设计划书/seo搜索推广费用多少
  • 大庆做网站公司/市场运营和市场营销的区别
  • 北京网站的优化/北京网络营销推广公司
  • 多个wordpress管理/北京seo优化哪家公司好