Docker环境下SpringBoot程序内存溢出(OOM)问题深度解析与实战调优

news2025/5/12 16:19:06

文章目录

      • 一、问题背景与现象还原
        • **1. 业务背景**
        • **2. 故障特征**
        • **3. 核心痛点**
        • **4. 解决目标**
      • 二、核心矛盾点分析
        • **1. JVM 与容器内存协同失效**
        • **2. 非堆内存泄漏**
        • **3. 容器内存分配策略缺陷**
      • 三、系统性解决方案
        • **1. Docker 容器配置**
        • 2. JVM参数优化(容器感知配置)
        • **3. Spring Boot 与 Tomcat 优化**
        • 4. 内存泄漏排查工具链
          • 4.1. arthas全局内存仪表盘(`dashboard`)
          • 4.2. arthas内存变化趋势监测(`memory`)
          • 4.3 arthas方法调用追踪(`trace`)
          • 4.4 arthas参数与返回值观察(`watch`)
        • 5.代码层面优化
          • 5.1 内存检测
          • 5.2 对象引用主动置空与生命周期管理
          • 5.3 资源释放标准化
          • 5.4 集合类内存优化
      • 四、典型故障场景复盘
        • 案例:MyBatis缓存导致Metaspace溢出
        • 案例:Netty堆外内存泄漏
      • 五、生产环境最佳实践
      • 六、兜底方案
        • 6.1 通过Semaphore 限制并发量
        • 6.2 实时计算内存使用情况,拦截内存溢出异常
        • 6.3 完整代码
      • 七、总结与思考

一、问题背景与现象还原

某SpringBoot数据平台在支撑ClickHouse海量数据导出时频繁崩溃,核心矛盾如下:

1. 业务背景
  • 单次导出需并发查询十余张视图(2亿~2000万行级数据)
  • 用户频繁选择全字段导出超宽时间范围筛选,导致单任务数据量激增
2. 故障特征
  • 提交超大请求后,系统在物理内存仅用3.4G/8G时即抛出OOM
  • 报错集中在非堆内存区域(如DirectBuffer、Metaspace),导致Druid连接池、Tomcat线程崩溃
  • 进程完全卡死,必须人工重启恢复
3. 核心痛点
  • 全量数据内存驻留式处理,单任务消耗GB级内存
  • 缺乏内存预警,用户无感知触发崩溃,日均3-5次运维介入
  • 服务中断影响全局业务,技术债务亟待解决
4. 解决目标

① 代码/JVM层优化降低常规内存消耗
② 极端场景下主动熔断任务,提示用户优化查询条件

初始启动命令:

docker run -d \
    --restart=always \
    -e JAVA_OPTS="-Xms1024m -Xmx4096m -Duser.timezone=Asia/Shanghai" \
    -e spring.profiles.active=prd \
    -p 9999:8080 \
    -v /app/logs:/app/logs \
    --name 服务名 \
    镜像:标签

二、核心矛盾点分析

1. JVM 与容器内存协同失效
  • 现象-Xmx4096m 仅设置堆内存上限,但未明确容器总内存限制,导致非堆内存(元空间、直接内存、线程栈等)超出容器默认限制,触发 OOM Killer 终止进程。

  • 验证方法

    docker stats --no-stream anesthesia-research  # 查看容器实际内存限制与使用情况
    cat /sys/fs/cgroup/memory/memory.stat         # 分析容器内存分布(包括缓存和RSS)
    
2. 非堆内存泄漏
  • 元空间泄漏:动态类加载未释放(如频繁反射、Spring AOP 代理类生成)。
  • 直接内存泄漏:NIO 缓冲区未释放(如 Netty、大文件操作未调用 Cleaner)。
  • 线程栈累积:默认线程栈大小 1MB,高并发场景下总占用可能超过容器剩余内存。
3. 容器内存分配策略缺陷
  • 未启用容器感知:旧版 Java 或未配置 -XX:+UseContainerSupport,导致 JVM 按宿主机内存分配堆,挤占非堆内存空间。
  • 静态分配堆内存-Xmx 固定值无法动态适配容器内存变化,易导致整体内存超限。

三、系统性解决方案

1. Docker 容器配置
  • 明确内存限制

    docker run
    

    中增加容器总内存约束(预留 25% 给非堆内存):

    docker run -d \
      -m 12g \                         # 容器总内存限制为 12GB(需大于 JVM 堆内存)
      --memory-swap=12g \              # 禁用 Swap 避免性能下降
      --restart=always \
      ...其他参数...
    
  • 监控容器级内存:

    docker stats 服务名  # 实时观察内存占用
    

在这里插入图片描述
在这里插入图片描述

2. JVM参数优化(容器感知配置)
-e JAVA_OPTS="
  -XX:+UseContainerSupport          # 启用容器内存感知(关键!)
  -XX:MaxRAMPercentage=75.0         # 动态分配堆内存占容器总内存的 75%(12G → 9G)
  -XX:InitialRAMPercentage=75.0     # 初始化堆75%(物理机)
  -XX:MaxMetaspaceSize=1g      # 限制元空间内存(防止类加载泄漏)
  -XX:MaxDirectMemorySize=2g        # 限制直接内存(NIO 场景必配)
  -Xss256k                          # 减少线程栈内存(适合高并发)
  -XX:+ExitOnOutOfMemoryError
  -XX:+HeapDumpOnOutOfMemoryError    # 自动生成堆转储文件
  -XX:NativeMemoryTracking=summary"
  • 关键调整:移除-Xmx,采用容器感知的百分比分配策略,允许JVM动态适配内存限制
  • 线程优化:将默认1MB线程栈缩小至256k,降低高并发场景下的内存消耗

优化后的启动命令:

docker run -d    --restart=always  -m 12g  --memory-swap=16g     -e JAVA_OPTS="-XX:+UseContainerSupport 
-XX:MaxRAMPercentage=75.0 
-XX:MaxMetaspaceSize=1g 
-XX:MaxDirectMemorySize=2g  
-Xss256k  
-XX:+UseG1GC--XX:+ExitOnOutOfMemoryError  
-XX:NativeMemoryTracking=summary  
-XX:+UnlockDiagnosticVMOptions  
-XX:+StartAttachListener  
-Duser.timezone=Asia/Shanghai"     
-e spring.profiles.active=prd     
-p 9999:8080     -v /app/logs:/app/logs     --name 服务名 镜像:标签
3. Spring Boot 与 Tomcat 优化
  • Tomcat 线程池调整

    (减少线程数及内存占用):

    -e SERVER_TOMCAT_THREADS_MAX=50 \      # 最大工作线程数(默认 200)
    -e SERVER_TOMCAT_ACCEPT_COUNT=50 \     # 等待队列长度(默认 100)
    -e SPRING_MAIN_LAZY_INITIALIZATION=true  # 延迟初始化 Bean 减少启动内存
    
  • 日志框架优化

    :限制 Logback 异步队列大小,避免日志堆积:

    <!-- logback-spring.xml -->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
      <queueSize>1024</queueSize>  <!-- 默认 256,过大易导致内存膨胀 -->
    </appender>
    
4. 内存泄漏排查工具链
工具使用场景命令示例
jmap生成堆转储分析大对象jmap -dump:format=b,file=heap.bin <pid>
arthas动态诊断内存泄漏点dashboard + heapdump
NMT追踪Native Memory分配详情jcmd <pid> VM.native_memory detail
Prometheus监控容器/JVM内存趋势配置jmx_exporter+Grafana看板
4.1. arthas全局内存仪表盘(dashboard

执行命令实时查看内存全景:

dashboard -i 2000  # 每2秒刷新一次

关键指标解读:

  • Heap:堆内存使用率(重点关注eden_spacetenured_gen
  • Non-Heap:元空间、代码缓存区等非堆内存
  • GC次数与耗时gc.ps_scavenge.count(Young GC次数)、gc.ps_marksweep.time(Full GC耗时)

在这里插入图片描述

4.2. arthas内存变化趋势监测(memory

持续追踪内存增长:

memory -t 60 -n 5  # 每60秒采样一次,显示前5名增长对象

典型内存泄漏特征:heapeden_space持续上涨且无锯齿状回收曲线

4.3 arthas方法调用追踪(trace

定位高内存消耗的接口:

trace com.example.UserController getUserInfo  # 追踪接口方法调用链路

输出包含:

  • 每个子调用的耗时与内存分配(通过-j参数显示内存变化)
  • 关联的SQL查询或外部服务调用(如发现拼接10万参数的SQL)
4.4 arthas参数与返回值观察(watch

监控接口入参和返回值对内存的影响:

watch com.example.OrderService createOrder "{params,returnObj}" -x 3  # 展开3层对象结构

典型场景:

  • 大对象参数(如List包含10万元素)
  • 缓存未释放的返回对象(如未设置TTL的缓存)
5.代码层面优化
5.1 内存检测

检测静态方法:

@Slf4j
public class MemoryMonitor {

    /**
     * 安全阈值(建议80%)
     */
    private static final double MEMORY_THRESHOLD = 80;

    public static void isMemoryCritical() {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        long maxMB = memoryBean.getHeapMemoryUsage().getMax() / (1024 * 1024);
        long usedMB = memoryBean.getHeapMemoryUsage().getUsed() / (1024 * 1024);
        double usedPercent = ((double) usedMB / maxMB) * 100;
        String formatted = String.format("%.2f%%", usedPercent);
        log.info("当前内存使用情况:最大内存={} MB,已使用内存={} MB", maxMB, usedMB);
        log.info("当前内存使用百分比={}", formatted); 
        if (usedPercent > MEMORY_THRESHOLD){
            throw new MemoryThresholdException("内存使用超过安全阈值,请及时处理!");
        }
    }
}

专属异常:

/**
 * MemoryThresholdException : 内存阈值异常
 *
 * @author zyw
 * @create 2025-04-11  10:44
 */

public class MemoryThresholdException extends RuntimeException {
    public MemoryThresholdException(String message) {
        super(message);
    }
}
5.2 对象引用主动置空与生命周期管理
  1. 显式置空无用对象
    通过将不再使用的对象引用设为 null,加速 GC 标记回收:

    List<Object> dataCache = new ArrayList<>();
    // 大数据处理完成后清理
    dataCache.clear();  // 清空集合内容
    dataCache = null;   // 释放集合对象引用
    
  2. 局部变量作用域控制
    缩小对象生命周期范围,避免长生命周期的变量持有短生命周期对象:

    public void processData() {
        // 大对象在方法内部创建,方法结束自动回收
        byte[] buffer = new byte[1024 * 1024]; 
        // ...处理逻辑...
    }  // buffer 超出作用域后自动回收
    
5.3 资源释放标准化
  1. Try-With-Resources 自动关闭
    对实现 AutoCloseable 接口的资源(文件、数据库连接等),强制使用自动关闭语法:

    try (Connection conn = dataSource.getConnection();
         PreparedStatement stmt = conn.prepareStatement(sql)) {
        // 执行查询...
    }  // 自动调用 close() 释放资源
    
  2. 线程局部变量清理
    避免 ThreadLocal 内存泄漏,使用后必须调用 remove()

    ThreadLocal<UserSession> userSession = new ThreadLocal<>();
    try {
        userSession.set(new UserSession());
        // ...业务逻辑...
    } finally {
        userSession.remove();  // 强制清理线程绑定数据
    }
    
5.4 集合类内存优化
  1. 静态集合使用弱引用
    替换静态 HashMapWeakHashMap,避免缓存对象无法回收:

    // 使用弱引用缓存(Key 无强引用时自动回收)
    Map<Long, UserSession> cache = new WeakHashMap<>();
    
  2. 大容量集合分块处理
    分批处理数据流,避免一次性加载到内存:

    try (BufferedReader reader = new BufferedReader(new FileReader("large.log"))) {
        String line;
        while ((line = reader.readLine()) != null) {
            processLine(line);  // 逐行处理,不缓存全部数据
        }
    }
    

四、典型故障场景复盘

案例:MyBatis缓存导致Metaspace溢出

某分页查询接口在高并发场景下频繁生成动态代理类,最终触发OutOfMemoryError: Metaspace。通过以下步骤定位:

  1. 日志分析:发现Metaspace使用量持续增长至512MB上限
  2. 堆转储验证:使用MAT工具分析发现org.apache.ibatis.reflection.javassist.JavassistProxyFactory类实例过多
  3. 解决方案:调整MyBatis的localCacheScope为STATEMENT,禁用全局缓存
案例:Netty堆外内存泄漏

某个TCP长连接服务运行24小时后出现OutOfMemoryError: Direct buffer memory,根本原因为未正确释放ByteBuf:

// 错误写法:未调用release()
ByteBuf buf = Unpooled.directBuffer(1024);
// 正确写法
try (ByteBuf buf = PooledByteBufAllocator.DEFAULT.directBuffer(1024)) {
    // 业务逻辑
} finally {
    buf.release(); 
}

通过-XX:MaxDirectMemorySize限制直接内存,并通过io.netty.leakDetectionLevel=paranoid开启泄漏检测。

五、生产环境最佳实践

  1. 防御性编程

    • 所有资源类对象(连接池、文件句柄)必须显式关闭
    • 使用WeakHashMap替代强引用缓存,避免内存驻留
  2. 监控体系构建

    # 容器级监控
    docker stats --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
    
    # JVM级监控
    jstat -gc <pid> 500  # 每500ms输出GC统计
    
  3. 混沌工程验证

    • 使用stress-ng工具模拟内存压力:
    stress-ng --vm 2 --vm-bytes 80% --timeout 10m
    
    • 验证JVM的-XX:+ExitOnOutOfMemoryError是否正常触发进程退出

六、兜底方案

6.1 通过Semaphore 限制并发量

配置:

/**
 * 限制并发数为1 (这里测试阶段暂设为1,可根据实际硬件配置权衡性能设置)
 */
private final Semaphore semaphore = new Semaphore(1);

使用:

        try {
            // 获取信号量,限制并发
            semaphore.acquire();
        } catch (InterruptedException e) {
            log.error("《==获取信号量时被中断,导出id:{},异常信息:{}", recordId, e.getMessage());
        } finally {
            // 释放信号量
            semaphore.release(); 
        }
6.2 实时计算内存使用情况,拦截内存溢出异常
@Slf4j
public class MemoryMonitor {

    /**
     * 安全阈值(建议80%)
     */
    private static final double MEMORY_THRESHOLD = 80;

    public static final String MEMORY_THRESHOLD_MESSAGE = "内存使用超过安全阈值,请缩小模板导出筛选范围或减少导出的变量!";

    public static void isMemoryCritical() {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        long maxMB = memoryBean.getHeapMemoryUsage().getMax() / (1024 * 1024);
        long usedMB = memoryBean.getHeapMemoryUsage().getUsed() / (1024 * 1024);
        double usedPercent = ((double) usedMB / maxMB) * 100;
        String formatted = String.format("%.2f%%", usedPercent);
        log.info("当前内存使用情况:最大内存={} MB,已使用内存={} MB", maxMB, usedMB);
        log.info("当前内存使用百分比={}", formatted);
        if (usedPercent > MEMORY_THRESHOLD){
            throw new MemoryThresholdException(MEMORY_THRESHOLD_MESSAGE);
        }
    }

    // 模拟内存溢出测试
    public static void main(String[] args) {
        List<byte[]> list = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            isMemoryCritical();
            // 每次分配100MB内存
            list.add(new byte[1024 * 1024 * 100]);
        }
    }
}
6.3 完整代码
/**
 * 限制并发数为1 (这里测试阶段暂设为1,可根据实际硬件配置权衡性能设置)
 */
private final Semaphore semaphore = new Semaphore(1);

@Async("asyncThreadPool")    
public void generateResearchDirectionFilesByTemplate(Long recordId, String fileName) {
        try {
            // 获取信号量,限制并发
            semaphore.acquire();
            // 异步执行的业务逻辑
            log.info("《==异步生成Excel文件中,导出申请id:{}==》", recordId);
            long l1 = System.currentTimeMillis();
            ExportRecords record = exportRecordsService.getById(recordId);

            try {
                String fileUrl = filePath + "/" + recordId + "/" + fileName + "-" + LocalDate.now() + ".xlsx";
                // 获取模板详情及写入数据
                Workbook workbook = exportAlgorithm(record.getProjectId(), record.getTemplateId());
                long l2 = System.currentTimeMillis();
                log.info("写入Excle耗时:{}", l2 - l1);
                // 上传到MINIO
                // 将 Workbook 转换为字节数组输入流
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                workbook.write(baos);
                byte[] workbookBytes = baos.toByteArray();
                ByteArrayInputStream bis = new ByteArrayInputStream(workbookBytes);
                PutObjectArgs args = PutObjectArgs.builder()
                        .bucket(minioConfig.getBucketName())
                        .object(fileUrl)
                        .stream(bis, bis.available(), -1)
                        .contentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
                        .build();
                minioClient.putObject(args);
                // 录入文件id
                record.setFileUrl(fileUrl);
                // 导出状态更新
                record.setFileStatus(StatusConstant.EXPORT_SUCCESSFULLY);
                long l4 = System.currentTimeMillis();
                log.info("《==异步生成Excel文件成功,导出id:{}==》,总耗时:{}", recordId, (l4 - l1));
                record.setTimeConsuming((l4 - l1));
                record.setErrorLog("无");
            } catch (ExcleException | MemoryThresholdException e) { // 自定义异常拦截预期报错
                record.setFileStatus(StatusConstant.EXPORT_FAILURE);
                record.setErrorMessage(e.getMessage());
            } catch (OutOfMemoryError e) {  // 拦截预期之外的内存溢出异常
                record.setFileStatus(StatusConstant.EXPORT_FAILURE);
                record.setErrorMessage(MemoryMonitor.MEMORY_THRESHOLD_MESSAGE);
            } catch (Exception e) {   // 程序报错拦截
                e.printStackTrace();
                record.setFileStatus(StatusConstant.EXPORT_FAILURE);
                if (Objects.isNull(e.getMessage())) {
                    record.setErrorLog("无报错日志");
                } else {
                    record.setErrorLog(e.getMessage().length() <= 500 ? e.getMessage() : e.getMessage().substring(0, 500));
                }
                long l5 = System.currentTimeMillis();
                record.setTimeConsuming((l5 - l1));
                log.info("《==异步生成Excel文件失败,导出id:{},异常信息:{}", recordId, e.getMessage());
                record.setErrorMessage(AnesthesiaResultCode.EXPORT_PROGRAM_ERROR.getMessage());
            } finally {
                // 修改导出记录下载状态
                exportRecordsService.updateById(record);
                // 内存清理
                System.gc();
            }
        } catch (InterruptedException e) {
            log.error("《==获取信号量时被中断,导出id:{},异常信息:{}", recordId, e.getMessage());
        } finally {
            semaphore.release(); // 释放信号量
        }
}

七、总结与思考

在容器化Java应用的运维中,内存管理需要从四个维度综合考量:

  1. 容器资源配额:合理设置Swap空间,平衡性能与稳定性
  2. JVM内存模型:理解堆/非堆内存的分配策略,避免参数冲突
  3. 应用代码质量:通过静态扫描(SonarQube)和动态分析(Arthas)预防泄漏
  4. 监控告警体系:建立容器/JVM/APM三层监控,实现异常早发现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2338474.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机网络】网络基础(协议,网络传输流程、Mac/IP地址 、端口号)

目录 1.协议简述2.网络分层结构2.1 软件分层2.2 网络分层为什么&#xff1f; 是什么&#xff1f;OSI七层模型TCP/IP五层&#xff08;或四层&#xff09;结构 3. 网络与操作系统之间的关系4.从语言角度理解协议5.网络如何传输局域网通信&#xff08;同一网段&#xff09; 不同网…

pgsql中使用jsonb的mybatis-plus和jps的配置

在pgsql中使用jsonb类型的数据时&#xff0c;实体对象要对其进行一些相关的配置&#xff0c;而mybatis和jpa中使用各不相同。 在项目中经常会结合 MyBatis-Plus 和 JPA 进行开发&#xff0c;MyBatis_plus对于操作数据更灵活&#xff0c;jpa可以自动建表&#xff0c;两者各取其…

使用MetaGPT 创建智能体(2)多智能体

先给上个文章使用MetaGPT 创建智能体&#xff08;1&#xff09;入门打个补丁&#xff1a; 补丁1&#xff1a; MeteGTP中Role和Action的关联和区别&#xff1f;这是这两天再使用MetaGPT时候心中的疑问&#xff0c;这里做个记录 Role&#xff08;角色&#xff09;和 Action&…

C# 使用.NET内置的 IObservable<T> 和 IObserver<T>-观察者模式

核心概念 IObservable<T> 表示 可观察的数据源&#xff08;如事件流、实时数据&#xff09;。 关键方法&#xff1a;Subscribe(IObserver<T> observer)&#xff0c;用于注册观察者。 IObserver<T> 表示 数据的接收者&#xff0c;响应数据变化。 三个核心…

Redis——网络模型之IO讲解

目录 前言 1.用户空间和内核空间 1.2用户空间和内核空间的切换 1.3切换过程 2.阻塞IO 3.非阻塞IO 4.IO多路复用 4.1.IO多路复用过程 4.2.IO多路复用监听方式 4.3.IO多路复用-select 4.4.IO多路复用-poll 4.5.IO多路复用-epoll 4.6.select poll epoll总结 4.7.IO多…

vue3 传参 传入变量名

背景&#xff1a; 需求是&#xff1a;在vue框架中&#xff0c;接口传参我们需要穿“变量名”&#xff0c;而不是字符串 通俗点说法是&#xff1a;在网络接口请求的时候&#xff0c;要传属性名 效果展示&#xff1a; vue2核心代码&#xff1a; this[_keyParam] vue3核心代码&…

旅游特种兵迪士尼大作战:DeepSeek高精准路径优化

DeepSeek大模型高性能核心技术与多模态融合开发 - 商品搜索 - 京东 随着假期的脚步日渐临近&#xff0c;环球影城等备受瞩目的主题游乐场&#xff0c;已然成为大人与孩子们心中不可或缺的节日狂欢圣地。然而&#xff0c;随之而来的庞大客流&#xff0c;却总让无数游客在欢乐的…

【MySQL】第一弹——MySQL数据库结构与操作

目录 一. 数据库介绍1.1 什么是数据库1.2 为什么要使用数据库1.3 主流数据库1.3.1 关系型数据库1.3.2 非关系型数据库 二. MySQL 的结构2.1 MySQL服务器和客户端2.2 MySQL服务器是如何组织数据的 三. 数据库的操作3.1 创建数据库语法格式示例 3.2 查看数据库语法格式示例 3.3 使…

Spring_MVC 快速入门指南

Spring_MVC 快速入门指南 一、Spring_MVC 简介 1. 什么是 Spring_MVC&#xff1f; Spring_MVC 是 Spring 框架的一个模块&#xff0c;用于构建 Web 应用程序。它基于 MVC&#xff08;Model-View-Controller&#xff09;设计模式&#xff0c;将应用程序分为模型&#xff08;M…

L38.【LeetCode题解】四数之和(双指针思想) 从汇编角度分析报错原因

目录 1.题目 2.分析 去重的代码 错误代码 3.完整代码 提交结果 1.题目 四数之和 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元…

字符串系列一>最长回文子串

目录 题目&#xff1a;解析&#xff1a;代码&#xff1a; 题目&#xff1a; 链接: link 解析&#xff1a; 代码&#xff1a; class Solution {public String longestPalindrome(String s) {char[] ss s.toCharArray();int n ss.length;int begin 0;//返回结果的起始字符串…

双击热备方案及不同方案的需求、方案对比

双击热备方案概述 一般实现双机热备的方案有三种,分别是共享存储双机热备方案、镜像双机热备方案、双机双柜双机热备方案,这三种方案对硬件要求不同,大家可以根据自身的业务应用特性来选择具体的双机热备方案以及对应的ServHA双机热备软件产品。 1、镜像双机热备 1.1镜像…

VSCODE插值表达式失效问题

GET https://cdn.jsdelivr.net/npm/vue2.6.14/dist/vue.js net::ERR_CONNECTION_-CSDN博客 更换正确的vue域名 GET https://cdn.jsdelivr.net/npm/vue2.6.14/dist/vue.js net::ERR_CONNECTION_ <script src"https://unpkg.com/vue2.6.14/dist/vue.js"></sc…

【失败】Gnome将默认终端设置为 Kitty

起因 一会儿gnome-terminal一会儿kitty终端&#xff0c;实在是受不了&#xff0c;决定取缔默认的gnome-terminal。 过程 在 Ubuntu 或 Debian 系统上&#xff1a; 确保 Kitty 已经安装。如果未安装&#xff0c;可以在终端中运行命令sudo apt install kitty -y进行安装。 使用系…

蓝桥杯:连连看

本题大意要我们在一个给定的nxm的矩形数组中找出符合条件的格子 条件如下&#xff1a; 1.数值相同 2.两个横坐标和纵坐标的差值相等&#xff08;由此可得是一个对角线上的格子&#xff09; 那么根据以上条件我们可以用HashMap来解决这个问题&#xff0c;统计对角线上数值相同…

Ext系列⽂件系统

Ext系列⽂件系统 1. 理解硬件1.1 磁盘的物理结构1.2 磁盘的存储结构1.3 磁盘的逻辑结构理解过程实际过程 1.4 CHS&&LBA地址 2. 引入文件系统块分区innode 3. Ext2文件系统3.1 宏观认识3.2 block group3.3 块组内部3.3.1 GDT&#xff08;Group Descriptor Table&#xf…

MTK-Android12 13 屏蔽掉Viewing full screen

去掉ROOM 开机第一次提示全屏弹框 文章目录 需求参考资料修改文件实现方案 解决思路grep 源码查找信息grep 查找 grep -rn "Viewing full screen" 找string 字段grep 查找 grep -rn immersive_cling_title 布局grep 查找 grep -rn layout.immersive_mode_cling 对应的…

GitHub创建远程仓库

使用GitHub创建远程仓库&#xff1a;从零开始实现代码托管与协作 前言 在当今软件开发领域&#xff0c;版本控制系统已成为开发者必备的核心工具。作为分布式版本控制系统的代表&#xff0c;Git凭借其强大的分支管理和高效的协作能力&#xff0c;已成为行业标准。而GitHub作为…

【AI部署】腾讯云GPU -—SadTalker的AI数字人访问web服务—未来之窗超算中心

访问部署在Cloud Studio上的web服务 当你把该项目部署在本地时&#xff0c;访问该服务的请求地址为http://localhost:8080/hello&#xff1b;当你把该项目部署在Cloud Studio工作台启动时&#xff0c;要想访问到该服务&#xff0c;需要先在工作台右侧打开访问链接面板&#xff…

fastdds:传输层SHM和DATA-SHARING的区别

下图是fastdds官方的图&#xff0c;清晰地展示了dds支持的传输层: 根据通信双方的相对位置(跨机器、同机器跨进程、同进程)的不同选择合适的传输层&#xff0c;是通信中间件必须要考虑的事情。 跨机器&#xff1a;udp、tcp 跨机器通信&#xff0c;只能通过网络&#xff0c; f…