OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【用户态内存调测】

news2024/9/24 4:39:28

往期知识点记录:

  • 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
  • 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
  • 持续更新中……

基本概念

Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、踩内存分析以及backtrace功能等维测手段,可以提高用户态内存相关问题的定位效率。

采用了对malloc/free接口进行插桩,保存关键节点信息,然后程序在申请和释放内存时进行内存节点完整性校验,最后在程序结束时通过统计节点信息得到内存统计信息并根据统计信息判断内存是否泄漏的设计思想。

运行机制

内存泄漏检查

对于每个进程,内存调测模块维护了128个链表(当前系统的线程最大数量为128个),每个链表的索引为线程ID。

申请内存时:保存关键信息到内存节点控制块,根据当前线程ID将内存节点控制块挂到对应链表;

释放内存时:根据需要释放的内存地址匹配内存节点控制块并将该控制块删除。

图1 堆内存节点信息链表

申请内存时,返回地址会被保存到LR寄存器中。进程运行过程中,系统会在内存节点控制块中添加疑似泄漏点对应的lr等信息。如下图所示:

图2 堆内存节点信息

其中,TID表示线程ID;PID表示进程ID;ptr表示申请的内存地址;size表示申请的内存大小;lr[n]表示函数调用栈地址,变量n的大小可以根据具体场景的需要进行配置。

释放内存时,将free等接口的入参指针与node的ptr字段进行匹配,如果相同则删除该内存节点控制块信息。

用户通过串口或文件等方式,将各个进程内存调测信息导出,利用addr2line工具将导出的信息转换成导致内存泄漏的代码行,便可以解决内存泄露问题。

图3 泄漏点代码行定位流程

堆内存统计

用户态线程堆内存使用统计具有一定的实际意义,统计线程申请的堆内存占比,为用户程序的内存使用优化提供数据支持。用户态堆内存统计模块主要涉及的接口为malloc和free。如上图所示,每个进程维护128个链表,链表索引即线程ID,申请内存时系统将ptr和size信息记录在内存节点控制块中并将节点控制块挂在以线程ID为头信息的链表上,堆内存释放时根据ptr从对应的链表上移除相应的堆内存块信息;同时计算出当前线程所持有的堆内存总的使用量,并更新当前进程的堆内存使用量和堆内存使用峰值。

内存完整性检查

  • 使用malloc申请内存(小于等于0x1c000 bytes时通过堆分配算法分配) 用户程序申请堆内存时,在堆内存节点处添加校验值等信息,如果校验值异常,则很有可能是前一块堆内存使用越界导致的(目前无法识别校验值被野指针破坏的场景)。在内存申请、释放时校验内存节点校验值的正确性,若内存节点被破坏,校验失败时则输出tid、pid及当前被踩节点前一块堆内存申请时保存的调用栈信息,通过addr2line工具可获得具体的代码行信息,辅助用户解决问题。

图4 node节点头信息添加校验值

free堆内存时,不会立即把该内存块释放掉,而是在内存中写入魔术数字0xFE,并放到free队列中(保证在一定时间内不会再被malloc函数分配),当有野指针或use-after-free的情况对该内存进行读取的操作时,能够发现数据异常,但是对于写操作则无法判断出来。

图5 free流程图

  • 使用malloc申请内存(大于0x1c000 bytes时通过mmap申请) 当malloc通过mmap申请大块内存时,在返回给用户使用的内存区间头和尾分别多申请一个页,一个页PAGE_SIZE当前为0x1000,这两个页分别通过mprotect接口设置权限为PROT_NONE(无可读可写权限),可以有效防止内存越界读写问题:越界读写数据时由于无读写权限而导致用户程序异常,根据异常调用栈信息可找到相应的代码逻辑。

图6 malloc通过mmap机制申请内存的内存布局

使用指导

接口说明

表1 内存调测功能

接口名描述
mem_check_init初始化内存检测模块。
watch_mem获取线程级堆内存使用信息。
check_leak检查是否有堆内存泄漏。
check_heap_integrity检查堆内存的完整性。
backtrace获取调用栈地址信息。
backtrace_symbols根据地址信息获取符号信息。
print_trace输出函数调用栈信息。

表2 调用栈回溯功能

接口名描述
backtrace获取调用栈地址信息。
backtrace_symbols根据地址信息获取符号信息。
print_trace输出函数调用栈信息。

使用说明

编译OpenHarmony工程时默认编译的是debug版本,即libc库已经集成内存调测相关的接口实现,用户可以根据具体需要决定是否使能内存调测功能。

堆内存调测功能提供两种方式供用户使用:接口调用及命令行参数。

  • 接口调用:优点是可以较精确的检查某一段代码逻辑的堆内存相关信息,缺点是需要修改用户代码。

  • 命令行参数:优点是无需修改用户代码,缺点是无法精确的校验某一段逻辑的堆内存信息。

说明: 内存调测功能使能后,进程退出时会默认进行一次堆内存泄漏和堆内存完整性检查。内存调测功能未使能时,堆内存统计、堆内存泄漏检查、堆内存完整性校验功能不会开启,调用相关调测接口无响应。

接口调用方式
示例代码

代码功能:显式调用调测模块的相关接口对用户代码进行内存校验。

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <debug.h> // 包含提供内存调测接口声明的头文件

#define MALLOC_LEAK_SIZE  0x300

void func(void)
{
    char *ptr = malloc(MALLOC_LEAK_SIZE);
    memset(ptr, '3', MALLOC_LEAK_SIZE);
}

int main()
{
    mem_check_init(NULL); // 通过串口输出内存调测信息,必须在用户程序第一次申请堆内存之前调用(一般在main函数入口调用),否则调测信息不准确。
    // mem_check_init("/storage/mem_debug.txt"); // 内存调测信息输出到/storage/mem_debug.txt文件中,如果该文件创建失败,则信息通过串口输出。
    char *ptr = malloc(MALLOC_LEAK_SIZE);
    memset(ptr, '1', MALLOC_LEAK_SIZE);

    watch_mem(); // 在当前代码逻辑处查看线程级内存统计信息。
    func();
    check_heap_integrity(); // 检查堆内存节点完整性。
    check_leak(); // 在当前代码逻辑处检查堆内存是否泄漏(一般在程序退出之前校验比较准确,若在malloc和free调用逻辑之间做校验,则结果不准确)。
    return 0;
}
c
编译
$ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos --sysroot=/home/<user-name>/directory/out/hispark_taurus/ipcamera_hispark_taurus/sysroot $(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a)

说明:

  • 本编译示例基于将编译器的路径写入环境变量中,即.bashrc文件中。

  • 编译用户程序及所需的lib库时,需要添加编译选项-funwind-tables,-rdynamic,-g,用于栈回溯。

  • -mfloat-abi=softfp,-mcpu=cortex-a7,-mfpu=neon-vfpv4编译选项用于指定具体的芯片架构、浮点数计算优化、fpu,与具体的libc库使用的编译选项保持一致,否则链接时可能出现找不到libc库文件。

  • -target arm-liteos用于指定编译器相关库文件路径。

  • –sysroot=/home//directory/out/hispark_taurus/ipcamera_hispark_taurus/sysroot用于指定编译器库文件搜索根目录,假设OpenHarmony工程代码存放路径为/home//directory。其中out/hispark_taurus/ipcamera_hispark_taurus路径为在编译时,hb set命令指定的具体产品,本示例选择的是ipcamera_hispark_taurus产品。

  • $(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a)用于指定相应的unwind库的路径。

调测信息
OHOS # ./mem_check
OHOS #
==PID:4== Heap memory statistics(bytes): // 堆内存统计信息
    [Check point]: // check点调用栈
        #00: <main+0x38>[0x86c] -> mem_check
        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so

    [TID: 18, Used: 0x320] // 18号线程堆内存占用,当前进程仅一个线程

==PID:4== Total heap: 0x320 byte(s), Peak: 0x320 byte(s)

Check heap integrity ok! // 堆内存完整性检查

==PID:4== Detected memory leak(s): // 内存泄漏信息及调用栈
    [Check point]:
        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
        #01: <main+0x44>[0x878] -> mem_check

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <main+0x1c>[0x850] -> mem_check
        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <func+0x14>[0x810] -> mem_check
        #01: <main+0x3c>[0x870] -> mem_check
        #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so

==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).

==PID:4== Detected memory leak(s):
    [Check point]:
        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
        #01: <exit+0x28>[0x111ec] -> /lib/libc.so

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <main+0x1c>[0x850] -> mem_check
        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <func+0x14>[0x810] -> mem_check
        #01: <main+0x3c>[0x870] -> mem_check
        #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so

==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).

Check heap integrity ok!
调用栈解析

提供parse_mem_info.sh脚本可以对调用栈进行解析,解析脚本存放的路径:kernel/liteos_a/tools/scripts/parse_memory/parse_mem_info.sh。利用脚本可以将相应的调测信息转换成具体的源码行号,如下命令所示,mem_debug.txt保存的是内存调测信息,elf1、elf2等文件是需要解析的elf文件。

$ ./parse_mem_info.sh mem_debug.txt elf1 elf2 elf3 ...

例如:

$ ./parse_mem_info.sh mem_debug.txt mem_check
Compiler is [gcc/llvm]: llvm
Now using addr2line ...

==PID:4== Heap memory statistics(bytes):
    [Check point]:
        #00: <main+0x38>[0x86c] at /usr1/xxx/TEST_ELF/mem_check.c:22
        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so

    [TID: 18, Used: 0x320]

==PID:4== Total heap: 0x320 byte(s), Peak: 0x320 byte(s)

Check heap integrity ok!

==PID:4== Detected memory leak(s):
    [Check point]:
        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
        #01: <main+0x44>[0x878] at /usr1/xxx/TEST_ELF/mem_check.c:28

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <main+0x1c>[0x850] at /usr1/xxx/TEST_ELF/mem_check.c:17
        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <func+0x14>[0x810] at /usr1/xxx/TEST_ELF/mem_check.c:9
        #01: <main+0x3c>[0x870] at /usr1/xxx/TEST_ELF/mem_check.c:24
        #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so

==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
命令行参数方式

对用户态进程进行内存相关的检查时,除了接口调用方式还可以通过命令行方式进行内存统计、内存泄漏或内存完整性检查。

--mwatch:初始化内存调测功能,注册信号。内存调测信息将从串口输出;
--mrecord <f_path>:初始化内存调测功能,注册信号。内存调测信息将保存至f_path文件,若f_path创建失败,则内存调测信息将从串口输出

在待调测的进程未退出时可使用信号机制获取对应信息:

kill -35 <pid> # 查看线程级堆内存占用
kill -36 <pid> # 检查是否存在堆内存泄漏
kill -37 <pid> # 检查堆内存头节点是否完整
示例代码

代码功能:构造内存问题利用命令行方式进行内存调测。

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

#define MALLOC_LEAK_SIZE  0x300

void func(void)
{
    char *ptr = malloc(MALLOC_LEAK_SIZE);
    memset(ptr, '3', MALLOC_LEAK_SIZE);
}

int main()
{
    char *ptr = malloc(MALLOC_LEAK_SIZE);
    memset(ptr, '1', MALLOC_LEAK_SIZE);
    func();
    while (1);
}
c
编译

参考接口调用章节里的编译。

使用mwatch参数命令
OHOS # ./mem_check --mwatch // 利用task命令可以查到mem_check进程的pid为4
OHOS #
OHOS # kill -35 4 // 查看堆内存统计信息
OHOS #
==PID:4== Heap memory statistics(bytes):
    [Check point]:
        #00: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so

    [TID: 18, Used: 0x640]

==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)

OHOS # kill -36 4 // 检查是否存在堆内存泄漏
OHOS #
==PID:4== Detected memory leak(s):
    [Check point]:
        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
        #01: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <main+0x14>[0x724] -> mem_check
        #01: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <func+0x14>[0x6ec] -> mem_check
        #01: <main+0x30>[0x740] -> mem_check
        #02: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so

==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).

OHOS # kill -37 4 // 检查堆内存头节点的完整性
OHOS #
Check heap integrity ok!
调用栈解析

将调测信息保存至test.txt文件中,利用脚本进行解析,获取内存泄漏的具体行号。

$ ./parse_mem_info.sh test.txt mem_check
Compiler is [gcc/llvm]: llvm
Now using addr2line ...

==PID:4== Detected memory leak(s):
    [Check point]:
        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
        #01: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <main+0x14>[0x724] at /usr1/xxx/TEST_ELF/mem_check.c:14
        #01: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so

    [TID:18 Leak:0x320 byte(s)] Allocated from:
        #00: <func+0x14>[0x6ec] at /usr1/xxx/TEST_ELF/mem_check.c:8
        #01: <main+0x30>[0x740] at /usr1/xxx/TEST_ELF/mem_check.c:19
        #02: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so

==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
使用mrecord参数命令
  1. 执行用户程序并指定记录内存调测信息的文件路径
    OHOS # ./mem_check --mrecord /storage/check.txt

  1. 利用kill -35 统计内存信息,该信息将会输出到文件中,使用cat命令查看
    OHOS # kill -35 4
    OHOS # Memory statistics information saved in /storage/pid(4)_check.txt

    OHOS # cat /storage/pid(4)_check.txt

    ==PID:4== Heap memory statistics(bytes):
        [Check point]:
            #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so

        [TID: 18, Used: 0x640]

    ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
  1. 利用kill -36 校验内存完整性,该信息将会输出到文件中,使用cat命令查看
    OHOS # kill -36 4
    OHOS # Leak check information saved in /storage/pid(4)_check.txt

    OHOS # cat /storage/pid(4)_check.txt

    ==PID:4== Heap memory statistics(bytes):
        [Check point]:
            #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so

        [TID: 18, Used: 0x640]

    ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)

    ==PID:4== Detected memory leak(s):
        [Check point]:
            #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
            #01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so

        [TID:18 Leak:0x320 byte(s)] Allocated from:
            #00: <main+0x14>[0x724] -> mem_check
            #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so

        [TID:18 Leak:0x320 byte(s)] Allocated from:
            #00: <func+0x14>[0x6ec] -> mem_check
            #01: <main+0x30>[0x740] -> mem_check
            #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so

    ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
  1. 利用kill -9 杀掉当前进程,进程退出后会默认校验内存完整性,该信息将会输出到文件中,使用cat命令查看
    OHOS # kill -9 4
    OHOS # Leak check information saved in /storage/pid(4)_check.txt

    Check heap integrity ok!

    OHOS # cat /storage/pid(4)_check.txt
    OHOS #
    ==PID:4== Heap memory statistics(bytes):
        [Check point]:
            #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so

        [TID: 18, Used: 0x640]

    ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)

    ==PID:4== Detected memory leak(s):
        [Check point]:
            #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
            #01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so

        [TID:18 Leak:0x320 byte(s)] Allocated from:
            #00: <main+0x14>[0x724] -> mem_check
            #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so

        [TID:18 Leak:0x320 byte(s)] Allocated from:
            #00: <func+0x14>[0x6ec] -> mem_check
            #01: <main+0x30>[0x740] -> mem_check
            #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so

    ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).

    ==PID:4== Detected memory leak(s):
        [Check point]:
            #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
            #01: <exit+0x28>[0x11b2c] -> /lib/libc.so

        [TID:18 Leak:0x320 byte(s)] Allocated from:
            #00: <main+0x14>[0x724] -> mem_check
            #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so

        [TID:18 Leak:0x320 byte(s)] Allocated from:
            #00: <func+0x14>[0x6ec] -> mem_check
            #01: <main+0x30>[0x740] -> mem_check
            #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so

    ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).

说明: 上述连续记录的信息会逐步追加到初始化时所指定的文件中,故最后cat文件时,文件中还包含历史记录的信息内容。

常见问题

UAF(Use after free)

  • 申请小块内存(不大于0x1c000 bytes) free之后:

    读操作:读取free之后的内存大概率是魔术数字(0xFEFEFEFE)

说明: free之后的堆内存不会立即释放进堆内存池,会先放至固定长度的队列中,并置魔术数字0xFE,队列满后会将先放至队列中的内存块释放进堆内存池

写操作:无法校验。

  • 申请大块内存(大于0x1c000 bytes) 堆内存由malloc通过调用mmap接口申请,free之后若仍访问该内存,则用户程序异常(该内存区间已被unmap)。

Double free

Double free时,用户程序将会异常退出。

堆内存节点被踩

  • 申请小块内存(不大于0x1c000 bytes)

堆内存节点被踩时,用户程序将会异常退出,并输出破坏被踩节点的可能的堆内存申请调用栈,对于野指针踩内存情况无法校验出来。例如用户程序mem_check中存在堆内存越界踩的情况,利用命令行方式可以获得踩内存的可能的具体位置。

    OHOS # ./mem_check --mwatch
    OHOS #
    ==PID:6== Memory integrity information:
        [TID:28 allocated addr: 0x272e1ea0, size: 0x120] The possible attacker was allocated from:
            #00: <malloc+0x808>[0x640e8] -> /lib/libc.so
            #01: <threadFunc1+0x7c>[0x21d0] -> mem_check

可以通过调用栈解析脚本对调用栈信息进行解析。

  • 申请大块内存(大于0x1c000 bytes)

堆内存由malloc通过mmap接口申请,申请得到的堆内存块前后各置一个size为PAGE_SIZE大小的区间,设置无读写权限,读写操作会触发用户程序异常。

最后

经常有很多小伙伴抱怨说:不知道学习鸿蒙开发哪些技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?

为了能够帮助到大家能够有规划的学习,这里特别整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

在这里插入图片描述

《鸿蒙 (Harmony OS)开发学习手册》(共计892页):https://gitcode.com/HarmonyOS_MN/733GH/overview

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

鸿蒙开发面试真题(含参考答案):

在这里插入图片描述

《OpenHarmony源码解析》:

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……
  • 系统架构分析
  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

图片

OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview

图片
在这里插入图片描述

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

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

相关文章

Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】

Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】 目录 Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】 一、简单介绍 二、状态模式&#xff08;State Pattern&#xff09; 1、什么时候使用状态模式 2、使用状态模式的…

Android RecyclerView 实现 GridView ,并实现点击效果及方向位置的显示

效果图 一、引入 implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30 二、使用步骤 1.Adapter public class UnAdapter extends BaseQuickAdapter<UnBean.ResultBean, BaseViewHolder> {private int selectedPosition RecyclerView.NO_POSITIO…

苹果电脑系统重磅更新——macOS Sequoia 15 系统 新功能一 览

有了 macoS Sequoia&#xff0c;你的工作效率将再次提升&#xff1a;快速调整桌面布局&#xff0c;一目了然地浏览网页重点&#xff0c;还可以通过无线镜像功能操控你的iPhone。 下面就来看看几项出色新功能&#xff0c;还有能够全面发挥这些功能的 App 和游戏。 macOS Sequo…

探秘 Web Bluetooth API:连接蓝牙设备的新利器

引言 随着物联网技术的快速发展&#xff0c;蓝牙设备在日常生活中扮演着越来越重要的角色。而在 Web 开发领域&#xff0c;Web Bluetooth API 的出现为我们提供了一种全新的方式来连接和控制蓝牙设备。本文将深入探讨 Web Bluetooth API 的使用方法和原理&#xff0c;帮助开发…

ElasticSearch的使用、Kibana和ES-Head可视化工具

ElasticSearch的使用、Kibana和ES-Head可视化工具 一、ElasticSearch概述1. ES2.IK分词器3. Kibana4.Head 二、安装1.ES安装2. 配置跨域和IK分词器3.Kibana安装4. Head安装 三、常用操作1. ES结构2. ES操作1. 索引的基本操作-创建索引-查看索引-修改索引-删除索引-特殊查看 2.文…

git笔记之在多个分支中复用某个分支提交的更改

git笔记之在多个分支中复用某个分支提交的更改 code review! 文章目录 git笔记之在多个分支中复用某个分支提交的更改1.实现该功能的 Bash 脚本示例2.这个脚本是否可以处理新添加的文件&#xff1f;3.该脚本使用前&#xff0c;应先使用下述脚本重置本地仓库所有分支与远程保持一…

Jenkins Pipeline 中通过勾选参数来控制是否构建 Docker 镜像

1.定义参数&#xff1a; 使用 booleanParam 定义一个布尔参数&#xff0c;示例如下 booleanParam(name: BUILD_DOCKER, description: 是否构建Docker镜像, defaultValue: false)2.使用参数&#xff1a; 在 stage 中&#xff0c;根据参数的值决定构建方式&#xff1a; stage(编…

HTTP 与 HTTPS 的三次握手与四次挥手详解

文章目录 HTTP 与 HTTPS 的三次握手与四次挥手详解一、HTTP 的三次握手与四次挥手1. HTTP 三次握手2. HTTP 四次挥手 二、HTTPS 的三次握手与四次挥手1. HTTPS&#xff08;无证书&#xff09;的三次握手与 SSL/TLS 握手2. HTTPS&#xff08;有证书&#xff09;的三次握手与 SSL…

vue-baidu-map的基本使用

前言 公司项目需求引入百度地图&#xff0c;由于给的时间比较短&#xff0c;所以就用了已经封装好了的vue-baidu-map 一、vue-baidu-map是什么&#xff1f; vue-baidu-map是基于vue.js封装的百度地图组件(官方文档) 二、使用步骤 1.下载插件 //我下载的版本 npm install …

注册讲堂 | 医疗器械组合包类产品常见问题(2)

问题一&#xff1a;组合包类产品的有效期应该如何确定&#xff1f; 组合包类产品的有效期以组件中最短有效期为最终产品有效期。 对于外购件&#xff0c;需要考虑组件购买时的剩余效期及影响效期主要因素&#xff0c;如材料老化、灭菌有效期等。 问题二&#xff1a;组合包类产…

【计算机网络强化】计网强化笔记

第一章 计算机网络体系结构 1.1 计算机网络概述 1.计算机网络由若干个节点和连接这些节点的链路组成 2. 3.计算机网络的组成 ①硬件、软件、协议 ②边缘部分和核心部分 ③通信子网和资源子网 4.电路交换、报文交换和分组交换 ①电路交换 分为三步&#xff1a;建立连接、…

基于SpringBoot+Vue的在线问诊管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

SQL面试常见题目

SQL面试常见题目涉及多个方面&#xff0c;包括数据查询、数据操作、表的设计与优化等。以下列举一些经典的SQL面试题目&#xff0c;并附上解析答案&#xff1a; 1. 查询一张表中重复的数据 题目&#xff1a; 给定一个表 employees&#xff0c;包含 id, name, salary 列。如何…

大型语言模型(Large Language Models)的介绍

背景 大型语言模型&#xff08;Large Language Models&#xff0c;简称LLMs&#xff09;是一类先进的人工智能模型&#xff0c;它们通过深度学习技术&#xff0c;特别是神经网络&#xff0c;来理解和生成自然语言。这些模型在自然语言处理&#xff08;NLP&#xff09;领域中扮…

丢失照片/消息/文件,当发现没有备份 Android 手机数据时急救方法

当人们发现他们没有备份 Android 手机数据时&#xff0c;通常为时已晚。但是&#xff0c;我们都不想永久丢失珍贵的照片&#xff0c; 消息和其他文件。这就是为什么您应该检查 遵循 5 大免费 Android 数据恢复工具和最佳替代品 他们。 排名前五的免费 Android 数据恢复软件 1.奇…

ELK-01-elasticsearch-8.15.1安装

文章目录 前言一、下载elasticsearch二、将tar包放到服务器三、解压tar包四、更改配置文件五、添加启动用户六、用elasticserch用户启动6.1 报错6.2 解决问题16.3 解决问题26.4 再次用elasticserch用户启动6.5 windows浏览器打开 七、设置开机自动启动7.1 创建启动脚本7.2 在脚…

【C++】二、数据类型 (同C)

2.1 整形 无特殊情况&#xff0c;一般用int 2.2实型&#xff08;浮点型&#xff09; 1. 单精度 foat 2. 双精度 double 输入小数时默认double&#xff0c;定义变量时可以使用float转换为单精度 3. 可使用科学计数法表示小数&#xff08;看得懂即可&#xff09; 4. 用于浮点型用…

Excel--DATEDIF函数的用法及参数含义

DATEDIF函数的用法为: DATEDIF(start_date,end_date,unit),start_date表示的是起始时间&#xff0c;end_date表示的是结束时间。unit表示的是返回的时间代码&#xff0c;是天、月、年等。如下: Datedif函数的参数含义unit参数返回值的意义"y"两个时间段之间的整年数…

推荐使用10款源代码加密软件,保护核心源代码,减少泄密风险

在现代企业中&#xff0c;保护核心源代码的安全变得尤为重要。源代码不仅是产品的核心资产&#xff0c;也是黑客和竞争对手的目标。一旦代码泄露&#xff0c;不仅可能导致产品安全漏洞&#xff0c;还会使企业的知识产权面临威胁。为了解决这一问题&#xff0c;源代码加密软件能…

Java反序列化利用链篇 | CC1链的第二种方式-LazyMap版调用链【本系列文章的分析重点】

文章目录 CC1链的第二种方式-LazyMap版调用链LazyMap构造payloadCC1的调用链 系列篇其他文章&#xff0c;推荐顺序观看~ Java反序列化利用链篇 | JdbcRowSetImpl利用链分析Java反序列化利用链篇 | CC1链_全网最菜的分析思路【本系列文章的分析重点】Java反序列化利用链篇 | CC1…