【实战JVM】-实战篇-05-内存泄漏及分析

news2024/11/16 5:26:53

【实战JVM】-实战篇-05-内存泄漏及分析

  • 1 内存溢出和内存泄漏
    • 1.1 常见场景
    • 1.2 解决内存溢出的方法
      • 1.2.1 发现问题
        • 1.2.1.1 top
        • 1.2.1.2 ViusalVM
        • 1.2.1.3 arthas
        • 1.2.1.4 Prometheus+Grafana
      • 1.2.2 堆内存状况对比
      • 1.2.3 内存泄漏原因-代码中
        • 1.2.3.1 equals()-hashCode()
        • 1.2.3.2 内部类引用外部类
        • 1.2.3.3 ThreadLocal的使用
        • 1.2.3.4 String的intern方法
        • 1.2.3.5 通过静态字段保存对象
        • 1.2.3.6 资源没有正常关闭
      • 1.2.4 内存泄漏原因-并发请求
        • 1.2.4.1 内存溢出
        • 1.2.4.2 内存泄漏
  • 2 诊断内存
    • 2.1 使用MAT诊断内存
    • 2.2 MAT检测内存泄漏原理
      • 2.2.1 生成内存快照观察深堆浅堆
    • 2.3 导出运行中内存的快照并分析
      • 2.3.1 jmap导出
      • 2.3.2 arthas导出
    • 2.4 分析超大堆内存快照
  • 3 实战
    • 3.1 分页查询文章接口的内存溢出
      • 3.1.1 设置参数重启jar包
      • 3.1.2 准备数据
      • 3.1.3 jmeter中导入测试脚本
      • 3.1.4 定位问题
      • 3.1.5 解决思路
    • 3.2 Mybatis导致的内存溢出
      • 3.2.1 定位问题
      • 3.2.2 解决思路
    • 3.3 导出大文件内存溢出
      • 3.3.1 k8s部署
      • 3.3.2 解决思路
    • 3.4 ThreadLocal使用时占用大量内存
      • 3.4.1 定位问题
      • 3.4.2 解决思路
    • 3.5 文章内容审核接口的内存问题
      • 3.5.1 定位问题
        • 3.5.1.1 线程池
        • 3.5.1.2 生产者-消费者使用队列
        • 3.5.1.3 消息中间件
  • 4 诊断和解决问题
    • 4.1 离线分析
    • 4.2 在线分析-arthas
    • 4.3 在线分析-btrace追踪
      • 4.3.1 添加依赖
      • 4.3.2 编写btrace脚本
      • 4.3.3 上传btrace工具及其脚本


1 内存溢出和内存泄漏

在这里插入图片描述

在这里插入图片描述

1.1 常见场景

  • 内存泄露导致溢出的常见场景是大型的Java后端应用中,在处理用户请求之后,没有及时将用户数据删除。随着用户请求的数量越来越多,内存泄漏的对象占满了堆内存,最终导致内存溢出。
  • 在这里插入图片描述

1.2 解决内存溢出的方法

在这里插入图片描述

1.2.1 发现问题

1.2.1.1 top

在这里插入图片描述

top

按M选择内存从大到小排序

1.2.1.2 ViusalVM

在这里插入图片描述

启动微服务com.itheima.jvmoptimize.JvmOptimizeApplication

在这里插入图片描述

远程连接查看visualvm

java -jar -Djava.rmi.server.hostname=182.92.117.86 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9122 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false SpringBoot-demo-1.0-SNAPSHOT.jar

访问不成功的话记得添加阿里云的安全组

在这里插入图片描述

生产环境禁止通过visualVM连接!只能在测试环境中查看。

1.2.1.3 arthas

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

启动arthas tutorial

nohup java -jar -Darthas.enable-detail-pages=true arthas-tunnel-server-3.7.1-fatjar.jar &

默认端口号8080,默认访问地址

http://182.92.117.86:8080/apps.html

微服务引入依赖并打包

<dependency>
    <groupId>com.taobao.arthas</groupId>
    <artifactId>arthas-spring-boot-starter</artifactId>
    <version>3.7.1</version>
</dependency>

先启动一个

nohup java -jar -Dserver.port=9527 -Darthas.http-port=9528 -Darthas.telnet-port=9529 jvm-optimize-0.0.1-SNAPSHOT.jar &

再启动一个

nohup java -jar -Dserver.port=9530 -Darthas.http-port=9531 -Darthas.telnet-port=9532 jvm-optimize-0.0.1-SNAPSHOT.jar &

在这里插入图片描述

一个tunnel,两个微服务

查看http://182.92.117.86:8080/apps.html

在这里插入图片描述

一点名字就进入arthas的页面

在这里插入图片描述

1.2.1.4 Prometheus+Grafana

在这里插入图片描述

添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>

    <exclusions><!-- 去掉springboot默认配置 -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

暴露所有端口

management:
  endpoint:
    metrics:
      enabled: true #支持metrics
    prometheus:
      enabled: true #支持Prometheus
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: jvm-test #实例名采集
  endpoints:
    web:
      exposure:
        include: '*' #开放所有端口

查询localhost:8881/actuator

在这里插入图片描述

查看所有bean属性

在这里插入图片描述

现在是通过监控springboot中的属性,也可以将jvm中其他的指标暴露出来。

引入依赖

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
    <scope>runtime</scope>
</dependency>
management:
  endpoint:
    metrics:
      enabled: true #支持metrics
    prometheus:
      enabled: true #支持Prometheus
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: jvm-test #实例名采集

打开http://localhost:8881/actuator/prometheus

在这里插入图片描述

查看堆信息

在这里插入图片描述

为我们的主机在阿里云中配置Prometheus监控

访问http://182.92.117.86:9527/actuator/prometheus

在这里插入图片描述

添加microMeter,监控jvm

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Micrometer大盘监控成功:

在这里插入图片描述

堆内存使用情况

在这里插入图片描述

堆中具体使用情况

在这里插入图片描述

Prometheus负责将服务器上的信息通过接口的方式收集到,并且把信息传输给Grafana,最后通过Grafana的仪表盘可视化出来

1.2.2 堆内存状况对比

在这里插入图片描述

1.2.3 内存泄漏原因-代码中

在这里插入图片描述

1.2.3.1 equals()-hashCode()

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

解决方法:

  • 在定义新实体类时始终重写equals()和hashCode()方法。
  • 重写时一定要确定使用了唯一的标识去区分不同的对象,比如用户的ID等。
  • hashmap使用时尽量使用编号ID等数据作为key,不要将整个实体类对象作为key存放。
  • 采用@Data来注释实体类避免出现此类情况
1.2.3.2 内部类引用外部类

在这里插入图片描述

问题一:

非静态的内部类默认会持有外部类,尽管代码上不使用外部类,所以如果有地方引用了这个非静态内部类,会导致外部类也会被引用,垃圾回收时无法回收这个外部类。

public class Outer{
    private byte[] bytes = new byte[1024 * 1024]; //外部类持有数据
    private String name  = "测试";
    class Inner{
        private String name;
        public Inner() {
            this.name = Outer.this.name;
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
//        System.in.read();
        int count = 0;
        ArrayList<Inner> inners = new ArrayList<>();
        while (true){
            if(count++ % 100 == 0){
                Thread.sleep(10);
            }
            inners.add(new Inner());
        }
    }
}

如果要用就要改为静态的内部类,并且引用外部类的静态属性

public class Outer{
    private byte[] bytes = new byte[1024 * 1024]; //外部类持有数据
    private static String name  = "测试";
    static class Inner{
        private String name;
        public Inner() {
            this.name = Outer.name;
        }
    }

可以理解为:非静态的内部类会保存自己是由哪个外部类对象所创建的,所以会持有该外部类对象的引用,而静态内部类属于类而不属于对象,所以可以直接创建。

问题二:

匿名内部类对象如果在非静态方法中被创建,则会持有调用者对象,垃圾回收时无法回收调用者。

public class Outer {
    private byte[] bytes = new byte[1024];
    public List<String> newList() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
        }};
        return list;
    }

    public static void main(String[] args) throws IOException {
        System.in.read();
        int count = 0;
        ArrayList<Object> objects = new ArrayList<>();
        while (true){
            System.out.println(++count);
            objects.add(newList());
        }
    }
}

使用内部类或匿名类,尽量改为静态类或静态方法

public class Outer {
    private byte[] bytes = new byte[1024];
    public static List<String> newList() {
        List<String> list = new ArrayList<String>() {{
            add("1");
            add("2");
        }};
        return list;
    }
1.2.3.3 ThreadLocal的使用

在这里插入图片描述

public class Demo5_1 {
    public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        while (true) {
            new Thread(() -> {
                threadLocal.set(new byte[1024 * 1024 * 10]);
            }).start();
            Thread.sleep(10);
        }
    }
}

单纯使用 new Thread(() -> {创建线程即使不会回收也不会内存泄漏,但是使用线程池就不一样了。

public class Demo5 {
    public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(Integer.MAX_VALUE, Integer.MAX_VALUE,
                0, TimeUnit.DAYS, new SynchronousQueue<>());
        int count = 0;
        while (true) {
            System.out.println(++count);
            threadPoolExecutor.execute(() -> {
                threadLocal.set(new byte[1024 * 1024]);
                //threadLocal.remove();
            });
            Thread.sleep(10);
        }
    }
}

使用完线程池的ThreadLocal之后记得remove移除

1.2.3.4 String的intern方法

在这里插入图片描述

1.2.3.5 通过静态字段保存对象

在这里插入图片描述

public class CaffineDemo {
    public static void main(String[] args) throws InterruptedException {
        Cache<Object, Object> build = Caffeine.newBuilder()
                .build();
        int count = 0;
        while (true){
            build.put(count++,new byte[1024 * 1024 * 10]);
            Thread.sleep(100L);
        }
    }
}

为缓存设置一个时间 .expireAfterWrite(Duration.ofMillis(100))

1.2.3.6 资源没有正常关闭

在这里插入图片描述

1.2.4 内存泄漏原因-并发请求

在这里插入图片描述

在这里插入图片描述

1.2.4.1 内存溢出

在Jmeter中添加线程组,每秒触发100次http请求

在这里插入图片描述

增加http请求

在这里插入图片描述

@GetMapping("/test")
public void test1() throws InterruptedException {
    byte[] bytes = new byte[1024 * 1024 * 100];//100m
    Thread.sleep(10 * 1000L);
}

在这里插入图片描述

修改启动参数

在这里插入图片描述

启动后大量报错

在这里插入图片描述

1.2.4.2 内存泄漏

在这里插入图片描述

在这里插入图片描述

粘贴到id的值那一行。

name同理,选择随机字符串RandomString,长度1000,哪些字符用于生成:26个字母

在这里插入图片描述

启动测试,每秒能处理8000个

在这里插入图片描述

2 诊断内存

2.1 使用MAT诊断内存

先把环境变量的jdk设为17再启动memoryanalyzer

在这里插入图片描述

在这里插入图片描述

添加虚拟机参数

-Xmx256m -Xms256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\File\StudyJavaFile\JavaStudy\JVM\shizhan\day05\resource\dump\test1.hprof

然后启动时用jmeter测试,控制台输出

在这里插入图片描述

用mat打开这个内存快照

在这里插入图片描述

在这里插入图片描述

点击detail查看详情

在这里插入图片描述

在这里插入图片描述

综合报告中同样能看到此类信息

在这里插入图片描述

2.2 MAT检测内存泄漏原理

在这里插入图片描述

在这里插入图片描述

2.2.1 生成内存快照观察深堆浅堆

在这里插入图片描述

public class HeapDemo {
    public static void main(String[] args) {
        TestClass a1 = new TestClass();
        TestClass a2 = new TestClass();
        TestClass a3 = new TestClass();
        String s1 = "itheima1";
        String s2 = "itheima2";
        String s3 = "itheima3";

        a1.list.add(s1);

        a2.list.add(s1);
        a2.list.add(s2);

        a3.list.add(s3);

        //System.out.print(ClassLayout.parseClass(TestClass.class).toPrintable());
        s1 = null;
        s2 = null;
        s3 = null;
        System.gc();
    }
}

class TestClass {
    public List<String> list = new ArrayList<>(10);
}

在这里插入图片描述

转换为支配树

在这里插入图片描述

添加虚拟机参数

-XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=D:/File/StudyJavaFile/JavaStudy/JVM/shizhan/day05/resource/dump/mattest.hprof

启动,控制台输出

Dumping heap to D:/File/StudyJavaFile/JavaStudy/JVM/shizhan/day05/resource/dump/mattest.hprof ...
Heap dump file created [2507919 bytes in 0.010 secs]

用mat打开,并且打开支配树

在这里插入图片描述

打印类的信息

引入

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>
public class StringSize {
    public static void main(String[] args) {
        //使用JOL打印String对象
        System.out.print(ClassLayout.parseClass(String.class).toPrintable());
    }
}

输出

java.lang.String object internals:
 OFFSET  SIZE     TYPE DESCRIPTION                               VALUE
      0    12          (object header)                           N/A
     12     4   char[] String.value                              N/A
     16     4      int String.hash                               N/A
     20     4          (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

0-11 是类头,12-15是char[] String.value,16-19是int String.hash,因为用的是64位系统,所以需要和8字节对齐,所以20-23是补齐8字节。

在这里插入图片描述

在这里插入图片描述

2.3 导出运行中内存的快照并分析

2.3.1 jmap导出

在这里插入图片描述

服务器中有3个,一个是arthas,两个是jvm-optimize

在这里插入图片描述

运行jmap命令输出9527的内存快照

jmap -dump:live,format=b,file=/home/jvm/dump/jvm-optimize-jmap.hprof 29317

在这里插入图片描述

2.3.2 arthas导出

访问182.92.117.86:8080/apps.html

随便进入一个

在这里插入图片描述

输入

heapdump --live /home/jvm/dump/jvm-optimize-arthas.hprof

在这里插入图片描述

在这里插入图片描述

得到俩,下载到本地后用mat打开

在这里插入图片描述

再看柱状图

在这里插入图片描述

要是一个对象的深堆过于的大的时候就可能发生内存泄漏。现在都在一个数量级。还算正常

2.4 分析超大堆内存快照

在这里插入图片描述

3 实战

在这里插入图片描述

3.1 分页查询文章接口的内存溢出

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.1.1 设置参数重启jar包

重新添加参数启动9527

nohup java -jar -Dserver.port=9527 -Darthas.http-port=9528 -Darthas.telnet-port=9529 -Xmx512m -Xms512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/jvm/dump/jvm9527.hprof jvm-optimize-0.0.1-SNAPSHOT.jar & 

打开Prometheus查看运行情况,现在只有100M还算ok

在这里插入图片描述

3.1.2 准备数据

在docker的mysql中生成了11w数据,方便后面查询

在这里插入图片描述

在这里插入图片描述

3.1.3 jmeter中导入测试脚本

在这里插入图片描述

在这里插入图片描述

这样等于150个线程×10000条数据保存到内存中

先查询一个

在这里插入图片描述

没什么问题,启动jmeter测试脚本

在这里插入图片描述

运行了五分钟都没溢出。

在这里插入图片描述

3.1.4 定位问题

直接看老师的视频吧,用mat分析内存结构,打开直方图和支配树,占用大的一个是rowData,一个是tomcat的线程。

先从线程入手,选择线程

在这里插入图片描述

在这里插入图片描述

发现是DemoQueryController在执行queryByPage这个方法

@GetMapping
public ResponseEntity<Page<TbArticle>> queryByPage(TbArticle tbArticle, int page,int size) {
	//size = Math.min(100,size);
    return ResponseEntity.ok(this.articleService.queryByPage(tbArticle, PageRequest.of(page,size)));
}

很多TbArticle对象只是被创建了,但是还没有返回,大量存在于内存中,在开发环境重新复现这个问题。

3.1.5 解决思路

在这里插入图片描述

选用一进行解决。

size = Math.min(100,size);

限制查询个数

3.2 Mybatis导致的内存溢出

在这里插入图片描述

3.2.1 定位问题

用3.1一样的分析方法,HandlerMethod->List->with outgoing references,定位到这里

在这里插入图片描述

@GetMapping
public ResponseEntity countIfAbsent(int size) {
    //随机生成批量id
    List<Integer> ids = new Random().ints(0, 1000000).
            limit(size).boxed().collect(Collectors.toList());

    return ResponseEntity.ok(this.articleService.countIfAbsent(ids));
}

会生成一个供mybatis去foreach的hashmap数组,占据大量空间

3.2.2 解决思路

在这里插入图片描述

3.3 导出大文件内存溢出

在这里插入图片描述

3.3.1 k8s部署

k8s搞不定,光听算了

3.3.2 解决思路

在这里插入图片描述

3.4 ThreadLocal使用时占用大量内存

在这里插入图片描述

3.4.1 定位问题

在这里插入图片描述

每次拦截用户信息都存在threadlocal中

public class UserInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        UserDataContextHolder.userData.set(new UserDataContextHolder.UserData());
         return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        UserDataContextHolder.userData.remove();
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

但是如果出现异常,postHandle中remove方法无法执行,用户信息就永远留在threadlocal中,所以需要吧remove移到afterCompletion中。

并且和tomcat的配置也有关系,最低保留100个线程进行处理,即使没有请求也有很多线程并不能被回收。

server:
  port: 8881
  tomcat:
    threads:
      min-spare: 100
      max: 500

修改为min-spare: 10,最小值为10,不能为0。

3.4.2 解决思路

在这里插入图片描述

3.5 文章内容审核接口的内存问题

在这里插入图片描述

3.5.1 定位问题

3.5.1.1 线程池

如果使用线程池处理异步请求

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

3.5.1.2 生产者-消费者使用队列

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

3.5.1.3 消息中间件

在这里插入图片描述

在这里插入图片描述

4 诊断和解决问题

在这里插入图片描述

4.1 离线分析

为jmeter添加插件
在这里插入图片描述

添加插件后,查看响应时间

在这里插入图片描述

大概30s就能响应

在这里插入图片描述

通过

jmap -dump:live,format=b,file=/home/jvm/dump/offline-jamp.hprof 28865

会导致较高的响应时间

4.2 在线分析-arthas

在这里插入图片描述

jmap -histo:live 28865 > /home/jvm/dump/online-jamp-histo.txt

在这里插入图片描述

监控一下UserEntity,在arthas中输入

stack com.itheima.jvmoptimize.entity.UserEntity -n 1

4.3 在线分析-btrace追踪

在这里插入图片描述

4.3.1 添加依赖

<dependencies>
    <dependency>
        <groupId>org.openjdk.btrace</groupId>
        <artifactId>btrace-agent</artifactId>
        <version>${btrace.version}</version>
        <scope>system</scope>
        <systemPath>D:\Software\software_with_code\btrace-v2.2.4-bin\libs\btrace-agent.jar</systemPath>
    </dependency>

    <dependency>
        <groupId>org.openjdk.btrace</groupId>
        <artifactId>btrace-boot</artifactId>
        <version>${btrace.version}</version>
        <scope>system</scope>
        <systemPath>D:\Software\software_with_code\btrace-v2.2.4-bin\libs\btrace-boot.jar</systemPath>
    </dependency>

    <dependency>
        <groupId>org.openjdk.btrace</groupId>
        <artifactId>btrace-client</artifactId>
        <version>${btrace.version}</version>
        <scope>system</scope>
        <systemPath>D:\Software\software_with_code\btrace-v2.2.4-bin\libs\btrace-client.jar</systemPath>
    </dependency>
</dependencies>

4.3.2 编写btrace脚本

@BTrace
public class TracingUserEntity {
        @OnMethod(
            clazz="com.itheima.jvmoptimize.entity.UserEntity",
            method="/.*/")
        public static void traceExecute(){
                jstack();
        }
}
  • method="/.*/"/表示开始和结束,.*表示监控clazz的所有方法
  • jstack();当调用当前类时,会打印当前所有栈信息

4.3.3 上传btrace工具及其脚本

上传btrace工具及其脚本,并且把他的bin目录放到环境变量中。

在这里插入图片描述

btrace 3785 TracingUserEntity.java 

在这里插入图片描述

已经挂载到当前进程中,我们用jmeter发送请求。

在这里插入图片描述

但是加了btrace后,响应时间不是一般的长,平均都在300ms以上

在这里插入图片描述

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

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

相关文章

相机等效焦距

1. 背景 物理焦距我们很熟悉,但是在接触实际的相机参数时,相机厂家会提到一个参数等效焦距,甚至有时候不提供物理焦距,这时候如果我们得到真实的物理焦距需要进行一定的转换.在介绍两者之间的转换关系前,先介绍一下等效焦距的由来. 如上图,假设在某一个镜头,其成像面会出现图…

Linux配置java,maven,marshalsec环境

文章目录 一. Linux配置java环境1.下载jdk文件2.解压tar.gz文件3.设置java环境变量4.验证是否成功 二. Linux配置maven环境1.下载压缩包2.解压tar.gz3. 配置环境变量 三. Linux配置marshalsec环境 一. Linux配置java环境 1.下载jdk文件 mkdir /opt/javawget https://repo.hua…

【设计模式深度剖析】【5】【结构型】【桥接模式】| 以电视和遥控器为例加深理解

&#x1f448;️上一篇:组合模式 | 下一篇:外观模式&#x1f449;️ 设计模式-专栏&#x1f448;️ 目 录 桥接模式(Bridge Pattern)定义英文原话是&#xff1a;直译理解 4个角色UML类图代码示例 应用优点缺点使用场景 示例解析&#xff1a;电视和遥控器UML类图 桥接模式…

【漏洞复现】DT-高清车牌识别摄像机 任意文件读取漏洞

0x01 产品简介 DT-高清 车牌识别摄像机是一款先进的安防设备&#xff0c;采用高清图像传感器和先进的识别算法&#xff0c;能够精准、快速地识别车牌信息。其高清晰该摄像机结合了智能识别技术&#xff0c;支持实时监宴图像质量确保在各种光照和天气条件下都能准确捕捉车牌信息…

【设计模式】JAVA Design Patterns——Factory Method(虚拟构造器模式)

&#x1f50d;目的 为创建一个对象定义一个接口&#xff0c;但是让子类决定实例化哪个类。工厂方法允许类将实例化延迟到子类 &#x1f50d;解释 真实世界例子 铁匠生产武器。精灵需要精灵武器&#xff0c;而兽人需要兽人武器。根据客户来召唤正确类型的铁匠。 通俗描述 它为类…

视频汇聚管理平台EasyCVR程序报错“create jwtSecret del server class:0xf98b6040”的原因排查与解决

国标GB28181协议EasyCVR安防视频监控平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;平台支持7*24小时实时高清视频监控&#xff0c;能同时播放多路监控视频流…

【学习笔记】Windows GDI绘图(八)画笔Pen与画刷Brush

文章目录 关于Pen改变Pen的宽度width和对齐方式Alignment带线帽的线段连接线条LineJoin自定义虚线用纹理填充线条 关于BrushHatchBrush阴影LinearGradientBrush线性渐变PathGradientBrush 详细示例Pen与Brush的属性与方法 关于Pen 改变Pen的宽度width和对齐方式Alignment 可以…

IntelliJ IDEA Ultimate 2024.1 Mac激活码 Java开发首选IDE

IntelliJ IDEA Ultimate 2024 搜Mac软件之家下载IDEA Mac中文版 IntelliJ IDEA Ultimate 2024是JetBrains公司推出的一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为专业开发者设计&#xff0c;支持多种编程语言和框架。它提供了一系列高级功能&…

【免费Web系列】JavaWeb实战项目案例五

这是Web第一天的课程大家可以传送过去学习 http://t.csdnimg.cn/K547r 新增员工 前面我们已经实现了员工信息的条件分页查询。 那今天我们要实现的是新增员工的功能实现&#xff0c;页面原型如下&#xff1a; ​ 首先我们先完成"新增员工"的功能开发&#xff0…

Linux--线程的分离、线程库的地址关系的理解、线程的简单封装(二)

线程系列&#xff1a; 线程的认识&#xff1a;讲解线程的概念和线程的基本控制 线程的分离 线程分离是指将一个线程从主线程中分离出来&#xff0c;使其能够独立运行。当一个线程被设置为分离状态时&#xff0c;它结束时系统会自动回收其资源&#xff0c;而不需要其他线程使用…

【喜报】科大睿智服务企业通过CMMI3级认证

​北京建投科信科技发展股份有限公司&#xff08;以下简称“北京建投科技” &#xff09;前身为北京银帝科技发展公司&#xff0c;成立于1993年&#xff0c;注册资本6,000万元&#xff0c;为中国建银投资有限责任公司&#xff08;简称“中国建投”&#xff09;的成员企业建投华…

ovs-vsctl错误:Port does not contain a column whoes name matches “--id“

出错的命令是: ovs-vsctl -- set Bridge br-int mirrors=@m -- --id=@snooper0 get Port snooper0\ -- --id=@patch-tun get Port patch-tun -- --id=@m create Mirror name=mymirror \ select

微软Edge浏览器深度解析:功能、同步、隐私与安全

微软Edge浏览器是微软公司开发的一款网页浏览器,它基于Chromium内核,提供了快速、安全和兼容性良好的网页浏览体验。以下是关于微软Edge浏览器的详细信息和使用指南: 微软Edge浏览器的主要特点: 1. 基于Chromium内核: 渲染引擎:Chromium内核是基于开源项目Blink的,它…

LNMP分布式搭建

一、准备三台主机 192.168.100.11 mysql 192.168.100.12 nginx 192.168.100.13 php 二、关闭防火墙及安全策略 systemctl stop firewalld setenforce 0 三、安装nginx&#xff08;192.168.100.11&#xff09; 1、添加nginx源 vim /etc/yum.repos.d/ng…

数据整理的Compact流程 (二)|OceanBase数据转储合并技术解读(二)

上篇文章《数据整理的Compact流程 &#xff08;一&#xff09;&#xff5c;OceanBase数据转储合并技术解读&#xff08;二&#xff09;》中&#xff0c;有讲解到&#xff0c;在OceanBase数据库中&#xff0c;当MemTable写满时&#xff0c;将其下刷到Mini SSTable的过程包含两个…

正邦科技(day4)

烧录 一、烧录固件二、 通讯模块升级1&#xff1a;USB的方式升级固件2&#xff1a;通过mqtt的方式升级固件3&#xff1a;切换环境 三、 烧录WiFi1&#xff1a;短接2&#xff1a;烧录脚本 设备注意事项&#xff1a; 第一种方式&#xff1a;通信模组和MCU都可以统一烧录BoodLoade…

数据结构---栈队列

栈和队列是我们数据结构中经常使用的数据结构&#xff0c;所以现在来了解一下栈和队列。 栈 特点&#xff1a; 栈是一种特殊的线性表&#xff0c;其中进行数据插入和弹出的部分叫做栈顶&#xff0c;另一端叫做栈底。 只允许数据从栈顶压入&#xff0c;从栈顶弹出即先进后出的…

Mac | Mac M 芯片应用意外退出问题

现象问题 电脑配置&#xff1a;MacBook Pro M1&#xff0c;系统 Sonoma 很多小伙伴新买了 M 芯片的 MacBook&#xff0c;在下载下应用后进行安装&#xff0c;安装成功后却无法打开&#xff0c;提示意外退出。报错如图 原因 部分应用过适配了 M 芯片&#xff0c;但还是有些应…

Windows配置共享文件夹

正文共&#xff1a;888 字 16 图&#xff0c;预估阅读时间&#xff1a;1 分钟 我们前面介绍了如果安装NAS工具&#xff08;废物利用&#xff0c;矿渣装个黑群晖。家庭小NAS搞起来&#xff01;&#xff09;&#xff0c;也介绍过如果配置远程桌面的多账号登录&#xff08;Windows…

Apache Nemo: A Framework for Optimizing Distributed Data Processing——论文泛读

TOCS 2021 Paper 论文阅读笔记整理 问题 针对资源和数据特性优化分布式数据处理的调度和通信&#xff0c;对于实现高性能至关重要。在最近的研究中广泛讨论的例子是&#xff1a;地理分布的资源[14&#xff0c;30&#xff0c;47&#xff0c;48]、廉价的瞬时资源[34&#xff0c…