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

news/2025/3/19 3:40:37/

目录

Kit

Apache JMeter

VisualVM

堆内存

jvm%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B-toc" name="tableOfContents" style="margin-left:40px">jvm内存模型

垃圾回收(Garbage Collection, GC)

新对象分配内存

GC步骤

MinorGC

性能优化

影响因素

优化

nginx动静分离

优化三级分类获取

Jvm参数配置堆区

测试


Kit

Apache JMeter

压力测试,模拟大量用户并发访问

VisualVM

监控、分析和调优 Java 应用程序的性能

VisualGC 插件:监控垃圾回收


堆内存

jvm%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B" name="jvm%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B">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.日志:仅报错

    javascript">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:

    javascript">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

    java">    @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

    java">    @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


    http://www.ppmy.cn/news/1580224.html

    相关文章

    Git的详细使用方法

    Git 是一个分布式版本控制系统&#xff0c;用于跟踪和管理代码的变更。以下是 Git 的详细使用方法&#xff1a; 1. 安装 Git Windows&#xff1a;从 Git 官网 下载安装包。 Linux&#xff08;Ubuntu/Debian&#xff09; sudo apt install git macOS&#xff1a; 使用 Homebr…

    Linux第六讲----git与gdb

    1.创建仓库并上传代码 打开gitee,新建仓库 按下图操作&#xff1a;之后点创建 在点击橙色的克隆下载&#xff1a;并复制 之后登录xshell并进入家目录 输入git clone 右键粘贴 如下图所示 之后我们进入for_delete cd for_delete/ 创建一个文件&#xff0c;code.c,输入如下内…

    【密码学——基础理论与应用】李子臣编著 第四章 SM4分组密码算法 课后习题

    免责声明 这里都是自己搓或者手写的。 里面不少题目感觉有问题或者我的理解有偏颇&#xff0c;请大佬批评指正&#xff01; 不带思考抄作业的请自动退出&#xff0c;我的并非全对&#xff0c;仅仅提供思维&#xff01; SM4的python实现 基于AI生成的SM4加密算法-CSDN博客 题…

    Word 小黑第27套

    对应大猫26 布局 行号-无 接受和拒绝修订&#xff1a;审阅 -显示标记 选特定人员 属性通过-文件添加 删除空行&#xff1a;两个段落标记 替换成 一个段落标记&#xff08;替换完再查找&#xff09; 检查文档并删除不可见内容。&#xff08;通过文件 信息 -检查信息&#xf…

    Android Room 框架领域层源码深度剖析(二)

    一、引言 在 Android 开发的架构设计中&#xff0c;领域层&#xff08;Domain Layer&#xff09;扮演着至关重要的角色。它是应用程序的核心业务逻辑所在之处&#xff0c;负责处理业务规则、协调数据流动以及实现用例。Android Room 框架虽然主要聚焦于数据持久化&#xff0c;…

    【WEB APIs】DOM-事件基础

    目录 1. 事件监听&#xff08;绑定&#xff09; 案例—关闭广告 案例-随机点名 2. 事件类型 2.1 鼠标事件 2.2 焦点事件 2.3 文本事件 3. 事件对象 案例—评论回车发布 4. 环境对象 5. 回调函数 6. 综合案例—tab栏切换 1. 事件监听&#xff08;绑定&#xff09; …

    Android菜单栏

    在Android中&#xff0c;菜单栏&#xff08;Menu&#xff09;是应用程序中常见的用户界面元素&#xff0c;用于提供各种操作选项。以下是关于Android菜单栏的基本介绍&#xff1a; 创建菜单资源 在项目的 res/menu 目录下创建一个XML文件来定义菜单内容&#xff0c;如 main…

    【mysql】不允许来自主机的链接错误解决方案

    错误信息 FHost 192.168.1.214 is not allowed to connect to this MySQL server 检查是否存在用户权限 SELECT user, host FROM mysql.user; 创建用户权限 CREATE USER root192.168.1.214 IDENTIFIED BY yourpassword; 更新用户权限 ALTER USER root192.168.1.214 IDEN…