dumpsys meminfo 流程中细节

news2024/11/24 12:55:01

源码基于:Android U

参考:

dumpsys meminfo 详解(R)

dumpsys meminfo 详解(U)

1. 命令入口 MemBinder

frameworks/base/services/core/java/com/android/server/am/AMS.java
 
   static class MemBinder extends Binder {
        ActivityManagerService mActivityManagerService;

 
        MemBinder(ActivityManagerService activityManagerService) {
            mActivityManagerService = activityManagerService;
        }
 
        @Override
        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            ...
        }
    }

2. 根据参数收集应用层 procs

dump 流程首先会调用 collectProcesses() 函数来解析需要dump 的进程 ProcessRecord,并且会将该 ProcessRecord list 以参数形式传入 dumpApplicationMemoryUsage() 函数,这也是 dump 的核心处理函数。

frameworks/base/services/core/java/com/android/server/am/AMS.java

    ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, int start, boolean allPkgs,
            String[] args) {
        synchronized (mProcLock) {
            return mProcessList.collectProcessesLOSP(start, allPkgs, args);
        }
    }

详细的代码可以查看 dumpsys meminfo 详解(U) 一文。

代码还是比较清晰的:

  • 如果命令行指定了pid,那么就收集这些进程;
  • 如果设定了packageName,就收集这些package;
  • 如果没有设定,则收集所有的 LRU process;

注意,前两点有可能收集的 proc 为空,因为设定的参数有可能是假的或者无法匹配。

这个时候终端上还提示No process:

shift:/ # dumpsys meminfo 12345
No process found for: 12345

3. 根据参数收集native层procs

在 dumpApplicationMemoryUsage() 函数中会看到这样一部分代码:

frameworks/base/services/core/java/com//android/server/am/AMS.java

        if (collectNative) {
            mi = null;
            final Debug.MemoryInfo[] memInfos = new Debug.MemoryInfo[1];
            mAppProfiler.forAllCpuStats((st) -> {
                if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
                    ...
                }
            });

            ArrayList<MemItem> catMems = new ArrayList<MemItem>();

            catMems.add(new MemItem("Native", "Native",
                    ss[INDEX_NATIVE_PSS], ss[INDEX_NATIVE_SWAP_PSS], ss[INDEX_NATIVE_RSS], -1));

            ...
        }

这部分代码是继处理应用层 LRU procs 之后,接着dump native 进程 procs 的内存。

其中入口需要 collectNative 为true,来看下初始化的地方:

final boolean collectNative = !opts.isCheckinRequest && numProcs > 1 && !opts.packages;

只要命令行没有配置 --checkin 参数,且没有配置 --package 参数,且LRU 的proc 大于1,则该值为 true。

其实,当dump 多个应用或者所有应用的 meminfo 时,变量 collectNative 被置true;如果只是打印单个应用的 meminfo 时该值为 false,所以最终不会打印。即,collectNative 也是用来区分 dump 所有应用meminfo 还是dump 单个应用的 meminfo。

当 collectNative 为true 时,另外一个很重要的事情就是通过 MemInfoReader.readMemInfo() 获取系统/proc/meminfo 的内存信息。

4. oomOnly 影响内存收集

当收集好 procs 之后,会通过 for 循环进行轮询,通过Debug 提供的内存获取函数,分别统计每个 pid 对应的 smaps 信息。

但,收集内存的函数有两个选择:

  • Debug.getMemoryInfo() 
  • Debug.getPss()
		if (!brief && !opts.oomOnly) {
			...
			if (!Debug.getMemoryInfo(st.pid, info)) {
				return;
			}
		} else {
			long pss = Debug.getPss(st.pid, tmpLong, memtrackTmp);
			...
		}

brief 是从 MemBinder 传入,默认为 false;

opts.oomOnly 是命令行是否带有 --oom 参数的flag,如果不带则调用 getMemoryInfo() 函数,如果带有则调用 getPss() 函数。区别在于 oomOnly 如果为 true时,不需要dump category 信息,而当 oomOnly 为false 时,需要 dump category 信息:

Total PSS by category:
    330,928K: EGL mtrack
    270,815K: Native
    240,812K: Dalvik
    168,739K: .apk mmap
    154,683K: .art mmap
    140,548K: .so mmap
    109,070K: .dex mmap
     99,964K: GL mtrack
     92,736K: Dalvik Other
     44,257K: .jar mmap
     36,406K: Other mmap
     33,019K: Stack
     31,307K: Unknown
     15,729K: .oat mmap
      1,670K: Other dev
      1,013K: Ashmem
        848K: .ttf mmap
          0K: Cursor
          0K: Gfx dev
          0K: Other mtrack

所以,getMemoryInfo() 中会统计更详细的每个 which_heap 的 pss、rss、swap 等等信息,而 getPss() 函数则只需要统计每个进程的 rss、pss、swap 整体信息即可。

4.1 Debug.getMemoryInfo()

frameworks/base/core/jni/android_os_Debug.cpp

static jboolean android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
        jint pid, jobject object)
{
    bool foundSwapPss;
    stats_t stats[_NUM_HEAP];
    memset(&stats, 0, sizeof(stats));

    if (!load_maps(pid, stats, &foundSwapPss)) {
        return JNI_FALSE;
    }

    struct graphics_memory_pss graphics_mem;
    if (read_memtrack_memory(pid, &graphics_mem) == 0) {
        stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
        stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
        stats[HEAP_GRAPHICS].rss = graphics_mem.graphics;
        stats[HEAP_GL].pss = graphics_mem.gl;
        stats[HEAP_GL].privateDirty = graphics_mem.gl;
        stats[HEAP_GL].rss = graphics_mem.gl;
        stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
        stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
        stats[HEAP_OTHER_MEMTRACK].rss = graphics_mem.other;
    }

    for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
        stats[HEAP_UNKNOWN].pss += stats[i].pss;
        stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss;
        stats[HEAP_UNKNOWN].rss += stats[i].rss;
        stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
        stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
        stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
        stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
        stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
        stats[HEAP_UNKNOWN].swappedOutPss += stats[i].swappedOutPss;
    }

    for (int i=0; i<_NUM_CORE_HEAP; i++) {
        env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
        env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss);
        env->SetIntField(object, stat_fields[i].rss_field, stats[i].rss);
        env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
        env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
        env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
        env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
        env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
        env->SetIntField(object, stat_fields[i].swappedOutPss_field, stats[i].swappedOutPss);
    }


    env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss);
    jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);

    jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
    if (otherArray == NULL) {
        return JNI_FALSE;
    }

    int j=0;
    for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
        otherArray[j++] = stats[i].pss;
        otherArray[j++] = stats[i].swappablePss;
        otherArray[j++] = stats[i].rss;
        otherArray[j++] = stats[i].privateDirty;
        otherArray[j++] = stats[i].sharedDirty;
        otherArray[j++] = stats[i].privateClean;
        otherArray[j++] = stats[i].sharedClean;
        otherArray[j++] = stats[i].swappedOut;
        otherArray[j++] = stats[i].swappedOutPss;
    }

    env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
    return JNI_TRUE;
}
  • 通过 load_maps() 从 /proc/pid/smaps 中获取进程的内存信息;
  • 通过 read_memtrack_memory() 通过 libmemtrack.so 获取 graphics 的内存信息;
  • 通过 env->SetIntField() 将 UNKNOWNdalvikheap 所属组的信息设置到 java 接口的参数 Meminfo 中;
  • 通过 otherArray 数组对应 java 端 MemoryInfo.otherStats[] 数组;

注意:

除了 HEAP_DALVIK 和 HEAP_NATIVE,其他所有 which_heap 的信息都会累加到 HEAP_UNKNOWN 中。这样,在 AMS 中会统计重要的字段信息,其他都认为是 unknown,如下:

Total PSS by category:
    330,928K: EGL mtrack
    270,815K: Native
    240,812K: Dalvik
    168,739K: .apk mmap
    154,683K: .art mmap
    140,548K: .so mmap
    109,070K: .dex mmap
     99,964K: GL mtrack
     92,736K: Dalvik Other
     44,257K: .jar mmap
     36,406K: Other mmap
     33,019K: Stack
     31,307K: Unknown
     15,729K: .oat mmap
      1,670K: Other dev
      1,013K: Ashmem
        848K: .ttf mmap
          0K: Cursor
          0K: Gfx dev
          0K: Other mtrack

4.2 Debug.getPss()

frameworks/base/core/jni/android_os_Debug.cpp

static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
        jlongArray outUssSwapPssRss, jlongArray outMemtrack)
{
    jlong pss = 0;
    jlong rss = 0;
    jlong swapPss = 0;
    jlong uss = 0;
    jlong memtrack = 0;

    struct graphics_memory_pss graphics_mem;
    if (read_memtrack_memory(pid, &graphics_mem) == 0) {
        pss = uss = rss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
    }

    ::android::meminfo::ProcMemInfo proc_mem(pid);
    ::android::meminfo::MemUsage stats;
    if (proc_mem.SmapsOrRollup(&stats)) {
        pss += stats.pss;
        uss += stats.uss;
        rss += stats.rss;
        swapPss = stats.swap_pss;
        pss += swapPss; // Also in swap, those pages would be accounted as Pss without SWAP
    } else {
        return 0;
    }

    if (outUssSwapPssRss != NULL) {
        int outLen = env->GetArrayLength(outUssSwapPssRss);
        if (outLen >= 1) {
            jlong* outUssSwapPssRssArray = env->GetLongArrayElements(outUssSwapPssRss, 0);
            if (outUssSwapPssRssArray != NULL) {
                outUssSwapPssRssArray[0] = uss;
                if (outLen >= 2) {
                    outUssSwapPssRssArray[1] = swapPss;
                }
                if (outLen >= 3) {
                    outUssSwapPssRssArray[2] = rss;
                }
            }
            env->ReleaseLongArrayElements(outUssSwapPssRss, outUssSwapPssRssArray, 0);
        }
    }

    if (outMemtrack != NULL) {
        int outLen = env->GetArrayLength(outMemtrack);
        if (outLen >= 1) {
            jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
            if (outMemtrackArray != NULL) {
                outMemtrackArray[0] = memtrack;
                if (outLen >= 2) {
                    outMemtrackArray[1] = graphics_mem.graphics;
                }
                if (outLen >= 3) {
                    outMemtrackArray[2] = graphics_mem.gl;
                }
                if (outLen >= 4) {
                    outMemtrackArray[3] = graphics_mem.other;
                }
            }
            env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
        }
    }

    return pss;
}
  • 通过 read_memtrace_memory() 统计graphics 的内存信息,并都累计到总的 pss、rss、uss、memtrack 中;
  • 通过 proc_mem.SmapsOrRollup() 函数统计 /proc/pid/smaps 中 Pss、Private_Clean、Private_Dirty、Rss、SwapPss 等信息;
  • 该函数返回的是进程的 pss,包括 swapPss。其他数据通过两个数组参数回传到 java端:
    • tmpLong 的三个元素分别是:uss、swap pss、rss;
    • memtrackTmp 的四个元素分别是:memtrack 总和、graphics、gl、other;

注意:

无论 getMemoryInfo() 之后在 AMS 中计算,还是getPss() 在 android_os_Debug.cpp 中计算,total 的pss,都是需要加上 swap out pss;

5. graphics 的内存收集函数

如上,无论是 getMemoryInfo() 还是 getPss() 函数,都会调用 read_memtrace_memory() 函数收集 graphics 的内存。

主要是通过libmemtrack.so,详细可以查看 dumpsys meminfo 详解(U) 一文。

6. dumpDetails 影响细节打印

opts.dumpDetails 是命令行是否带有 -a -s 参数的 flag,当带有该参数时需要收集进程的所有category 信息。所以,收集函数是调用 getMemoryInfo(),而不是 getPss()。

另外,当该 flag 为true时,dump 流程会调用 thread.dumpMemInfo() 函数,会通过 getRuntime() 获取app 进程 dalvik 的 totalMemory 和 freeMemory,并计算出 dalvikAllocated,得到app 进程虚拟机内存使用情况。 详细可以查看 dumpsys meminfo 详解(U) 一文。

最终结果如下图:

7. which_heap 的概念

whick_heap 的概念在 android_os_Debug.cpp 中提出,用以区分某 pid 应用的内存。在 native 端有个 enum:

frameworks/base/core/jni/android_os_Debug.cpp

enum {
    HEAP_UNKNOWN,
    HEAP_DALVIK,
    HEAP_NATIVE,

    HEAP_DALVIK_OTHER,
    HEAP_STACK,
    HEAP_CURSOR,
    HEAP_ASHMEM,
    HEAP_GL_DEV,
    HEAP_UNKNOWN_DEV,
    HEAP_SO,
    HEAP_JAR,
    HEAP_APK,
    HEAP_TTF,
    HEAP_DEX,
    HEAP_OAT,
    HEAP_ART,
    HEAP_UNKNOWN_MAP,
    HEAP_GRAPHICS,
    HEAP_GL,
    HEAP_OTHER_MEMTRACK,

    ...

    _NUM_HEAP,
    _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
    _NUM_CORE_HEAP = HEAP_NATIVE+1
};

当然,该分类对应 Debug.MemoryInfo中有相同值的静态变量,如下:

frameworks/base/core/java/android/os/Debug.java

        public static final int HEAP_UNKNOWN = 0;
        /** @hide */
        public static final int HEAP_DALVIK = 1;
        /** @hide */
        public static final int HEAP_NATIVE = 2;

        /** @hide */
        public static final int OTHER_DALVIK_OTHER = 0;
        /** @hide */
        public static final int OTHER_STACK = 1;
        /** @hide */
        public static final int OTHER_CURSOR = 2;
        /** @hide */
        ...

注意:

系统将 smaps 中的内存分成了三大块:dalviknative 以及 unknown,并且系统将 unknown 又细分了17 类。

 

7.1 dumpsys meminfo 中的category

Total PSS by category:
    260,780K: Native
    255,280K: EGL mtrack
    213,776K: Dalvik
    186,632K: .apk mmap
    131,867K: .so mmap
    110,157K: .dex mmap
    109,952K: GL mtrack
     87,703K: Dalvik Other
     79,525K: .art mmap
     47,593K: .jar mmap
     41,380K: Other mmap
     31,408K: Stack
     29,258K: Unknown
     17,319K: .oat mmap
      1,544K: Other dev
        887K: Ashmem
        510K: .ttf mmap
          0K: Cursor
          0K: Gfx dev
          0K: Other mtrack

其中,除了 Native、Dalvik 和 Unknown,其他的是 unknown 细分出来的 17 类。

而,上面的 Unknown 是从大块 Unknown去除其他 17 类之后的内存。

7.2 smaps 中vma 与 HEAP 枚举对照

对照表可以查看 dumpsys meminfo 详解(U) 一文。

8. total pss

totap pss 分两大块:应用进程的 total pss + native 进程的 total pss。每个进程的 total pss 有如下的公式:

total pss = dalvikPss + nativePss + otherPss + total swap out pss;

即,系统的 total pss 为所有应用进程的total pss 与所有native 进程的 total pss 之和。

其中每个进程的 total swap out pss 满足:

frameworks/base/core/java/android/os/Debug.java

        public int getTotalSwappedOutPss() {
            return dalvikSwappedOutPss + nativeSwappedOutPss + otherSwappedOutPss;
        }

9. cached pss

cached pss 为应用进程中 oomAdj 大于等于 ProcessList.CACHED_APP_MIN_ADJ 的所有进程 total pss 之和。

10. 系统 memory

详细可以查看 dumpsys meminfo 详解(U) 一文。

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

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

相关文章

Python-VBA函数之旅-print函数

目录 一、print函数的常见应用场景 二、print函数使用注意事项 三、如何用好print函数&#xff1f; 1、print函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a;神奇夜光杯-CSDN博客 一、print函数的常见应…

Prometheus 2: 一个专门评估其他语言模型的开源语言模型(续集)

普罗米修斯的续集来了。 专有的语言模型如 GPT-4 经常被用来评估来自各种语言模型的回应品质。然而,透明度、可控制性和可负担性等考虑强烈促使开发专门用于评估的开源语言模型。另一方面,现有的开源评估语言模型表现出关键的缺点:1) 它们给出的分数与人类给出的分数存在显著差…

Unity射击游戏开发教程:(11)制造敌人爆炸

增加爆炸效果 爆炸一切都变得更好!尤其是当你消灭敌人时。在这篇文章中,我将讨论如何在敌人被击中时为其添加爆炸动画。 在敌人的预制件中,您将需要创建一个新的动画。查看控制动画的动画器,默认情况下将从进入动画到敌人爆炸动画。这意味着,一旦敌人被实例化,敌人爆炸…

02、Kafaka 简介

02、Kafka 简介 1、 Kafka 简介 Apache Kafka 是一个分布式的发布-订阅消息系统&#xff0c;最初由 LinkedIn 公司开发&#xff0c;并在 2010 年贡献给了 Apache 软件基金会&#xff0c;成为一个顶级开源项目。Kafka 设计之初是为了满足高吞吐量、可扩展性、持久性、容错性以…

深度学习中的不确定性量化:技术、应用和挑战综述(一)

不确定性量化(UQ)在减少优化和决策过程中的不确定性方面起着关键作用&#xff0c;应用于解决各种现实世界的科学和工程应用。贝叶斯近似和集成学习技术是文献中使用最广泛的两种UQ方法。在这方面&#xff0c;研究人员提出了不同的UQ方法&#xff0c;并测试了它们在各种应用中的…

10.Java对象内置结构

文章目录 Java对象内置结构1.Java对象的三个部分1.1.对象头1.2.对象体1.3.对齐字节 2.对象结构中核心字段的作用2.1.MarkWord(标记字)2.2.Class Pointer(类对象指针)2.3.Array Length(数组长度)2.4.对象体2.5.对齐字节 3.Mark Word的结构信息3.1.不同锁状态下的Mark Word字段结…

GraphGPT——图结构数据的新语言模型

在人工智能的浪潮中&#xff0c;图神经网络&#xff08;GNNs&#xff09;已经成为理解和分析图结构数据的强大工具。然而&#xff0c;GNNs在面对未标记数据时&#xff0c;其泛化能力往往受限。为了突破这一局限&#xff0c;研究者们提出了GraphGPT&#xff0c;这是一种为大语言…

部署YUM仓库以及NFS共享服务

YUM仓库部署 一.YUM概述 YUM仓库源是一种软件包管理工具&#xff0c;用于在Linux系统上安装、更新和删除软件包。YUM仓库源包含了软件包的元数据信息和实际的软件包文件。用户可以通过配置YUM仓库源&#xff0c;从中下载和安装软件包。 常见的YUM仓库源包括&#xff1a; 本…

pip install dotenv出现error: subprocess-exited-with-error的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

springboot+vue+elementui实现校园互助平台大作业、毕业设计

目录 一、项目介绍 二、项目截图 管理后台 1.登录&#xff08;默认管理员账号密码均为&#xff1a;admin&#xff09; 2. 用户管理 ​编辑 3.任务管理 互助单&#xff08;学生发布&#xff09; 行政单&#xff08;教师发布&#xff09; ​编辑 审核&#xff08;退回需…

36.Docker-Dockerfile自定义镜像

镜像结构 镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。 镜像是分层机构&#xff0c;每一层都是一个layer BaseImage层&#xff1a;包含基本的系统函数库、环境变量、文件系统 EntryPoint:入口&#xff0c;是镜像中应用启动的命令 其他&#xff1a;在…

电脑c盘太满了,如何清理 电脑杀毒软件哪个好用又干净免费 电脑预防病毒的软件 cleanmymacX有必要买吗 杀毒软件排行榜第一名

杀毒软件通常集成监控识别、病毒扫描和清除、自动升级、主动防御等功能&#xff0c;有的杀毒软件还带有数据恢复、防范黑客入侵、网络流量控制等功能&#xff0c;是计算机防御系统的重要组成部分。 那么&#xff0c;对于Mac电脑用户来说&#xff0c;哪款电脑杀毒软件更好呢&a…

PCB光控打孔机第二版程序(一)

/*PCB机程序 XY同时启动 L9751 CODE61068 2018 6 19 08:00 固定位置释放吸盘*/ /*修正寻点第十二条结束调用计算坐标L5091&#xff0c;自动运行Y计算L6280 6281***/ /*** 开外部中断2关闭定时器2XY轴输出信号&#xff0c;自动运行循环检测外部中断高电平重启XY轴输出信号 增加寻…

LeetCode 难题解析 —— 正则表达式匹配 (动态规划)

10. 正则表达式匹配 思路解析 这道题虽然看起来不难理解&#xff0c;但却存在多种可能&#xff0c;当然这种可能的数量是有限的&#xff0c;且其规律对于每一次判别都使用&#xff0c;所以自然而然就想到用 动态规划 的方法啦 接下来逐步分析可能的情况&#xff1a; &#x…

探索中位数快速排序算法:高效寻找数据集的中间值

在计算机科学领域&#xff0c;寻找数据集的中位数是一个常见而重要的问题。而快速排序算法作为一种高效的排序算法&#xff0c;可以被巧妙地利用来解决中位数查找的问题。本文将深入探讨中位数快速排序算法的原理、实现方法以及应用场景&#xff0c;带你领略这一寻找中间值的高…

[UDS][OTA] 自定义 IntelHEX (IHEX) format read/write library in C

参考修改 参考github的MIT协议开源项目 ihex 改写的代码 https://gitee.com/liudegui/intelhex-c 修改点&#xff1a; 修改Makefile脚本&#xff0c;支持x86_X64平台和aarch64平台将默认读取行长度设置为16位删除与ihex和bin之间的转换无关的示例代码 十六进制描述 HEX格式…

C++容器——deque

deque容器 定义&#xff1a;动态数组&#xff0c;是一种双向开口的线性容器&#xff0c;意味着你不仅可以像在普通队列的末尾添加和移除元素&#xff0c;还可以在前端执行这些操作。 与其他容器相比不同的点&#xff1a; 与vector的主要区别&#xff1a; 连续性&#xff1a;…

基于 Spring Boot 博客系统开发(六)

基于 Spring Boot 博客系统开发&#xff08;六&#xff09; 本系统是简易的个人博客系统开发&#xff0c;为了更加熟练地掌握 SprIng Boot 框架及相关技术的使用。&#x1f33f;&#x1f33f;&#x1f33f; 基于 Spring Boot 博客系统开发&#xff08;五&#xff09;&#x1f…

商标不做检索分析,直接申请通过率很低!

今天有个网友拿到驳回通知书找到普推知产老杨&#xff0c;让分析驳回通过率如何&#xff0c;他主要两个文字商标和两个图形商标&#xff0c;文字商标都是两个字的&#xff0c;两个字的商标名称基本都有相同或高近&#xff0c;引用了好几个高度近似&#xff0c;直接做驳回复审通…

Unity 性能优化之光照优化(七)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、测试目的一、实时光源是什么&#xff1f;二、开始测试1.场景中只有一个光照的数值情况2.添加4个点光源后4.结果 总结 前言 实时光源数量越多&#x…