[转帖]全网最硬核 JVM 内存解析 - 4.Java 堆内存大小的确认

https://cloud.tencent.com/developer/article/2277323

 

个人创作公约:本人声明创作的所有文章皆为自己原创,如果有参考任何文章的地方,会标注出来,如果有疏漏,欢迎大家批判。如果大家发现网上有抄袭本文章的,欢迎举报,并且积极向这个 github 仓库 提交 issue,谢谢支持~ 另外,本文为了避免抄袭,会在不影响阅读的情况下,在文章的随机位置放入对于抄袭和洗稿的人的“亲切”的问候。如果是正常读者看到,笔者在这里说声对不起,。如果被抄袭狗或者洗稿狗看到了,希望你能够好好反思,不要再抄袭了,谢谢。 今天又是干货满满的一天,这是全网最硬核 JVM 解析系列第四篇,往期精彩:

  • 全网最硬核 TLAB 解析
  • 全网最硬核 Java 随机数解析
  • 全网最硬核 Java 新内存模型解析

本篇是关于 JVM 内存的详细分析。网上有很多关于 JVM 内存结构的分析以及图片,但是由于不是一手的资料亦或是人云亦云导致有很错误,造成了很多误解;并且,这里可能最容易混淆的是一边是 JVM Specification 的定义,一边是 Hotspot JVM 的实际实现,有时候人们一些部分说的是 JVM Specification,一部分说的是 Hotspot 实现,给人一种割裂感与误解。本篇主要从 Hotspot 实现出发,以 Linux x86 环境为主,紧密贴合 JVM 源码并且辅以各种 JVM 工具验证帮助大家理解 JVM 内存的结构。但是,本篇仅限于对于这些内存的用途,使用限制,相关参数的分析,有些地方可能比较深入,有些地方可能需要结合本身用这块内存涉及的 JVM 模块去说,会放在另一系列文章详细描述。最后,洗稿抄袭狗不得 house

本篇全篇目录(以及涉及的 JVM 参数):

  1. 从 Native Memory Tracking 说起(全网最硬核 JVM 内存解析 - 1.从 Native Memory Tracking 说起开始)
    1. Native Memory Tracking 的开启
    2. Native Memory Tracking 的使用(涉及 JVM 参数:NativeMemoryTracking
    3. Native Memory Tracking 的 summary 信息每部分含义
    4. Native Memory Tracking 的 summary 信息的持续监控
    5. 为何 Native Memory Tracking 中申请的内存分为 reserved 和 committed
  2. JVM 内存申请与使用流程(全网最硬核 JVM 内存解析 - 2.JVM 内存申请与使用流程开始)
    1. Linux 下内存管理模型简述
    2. JVM commit 的内存与实际占用内存的差异
      1. JVM commit 的内存与实际占用内存的差异
    3. 大页分配 UseLargePages(全网最硬核 JVM 内存解析 - 3.大页分配 UseLargePages开始)
      1. Linux 大页分配方式 - Huge Translation Lookaside Buffer Page (hugetlbfs)
      2. Linux 大页分配方式 - Transparent Huge Pages (THP)
      3. JVM 大页分配相关参数与机制(涉及 JVM 参数:UseLargePages,UseHugeTLBFS,UseSHM,UseTransparentHugePages,LargePageSizeInBytes
  3. Java 堆内存相关设计(全网最硬核 JVM 内存解析 - 4.Java 堆内存大小的确认开始)
    1. 通用初始化与扩展流程
    2. 直接指定三个指标的方式(涉及 JVM 参数:MaxHeapSize,MinHeapSize,InitialHeapSize,Xmx,Xms
    3. 不手动指定三个指标的情况下,这三个指标(MinHeapSize,MaxHeapSize,InitialHeapSize)是如何计算的
    4. 压缩对象指针相关机制(涉及 JVM 参数:UseCompressedOops)(全网最硬核 JVM 内存解析 - 5.压缩对象指针相关机制开始)
      1. 压缩对象指针存在的意义(涉及 JVM 参数:ObjectAlignmentInBytes
      2. 压缩对象指针与压缩类指针的关系演进(涉及 JVM 参数:UseCompressedOops,UseCompressedClassPointers
      3. 压缩对象指针的不同模式与寻址优化机制(涉及 JVM 参数:ObjectAlignmentInBytes,HeapBaseMinAddress
    5. 为何预留第 0 页,压缩对象指针 null 判断擦除的实现(涉及 JVM 参数:HeapBaseMinAddress
    6. 结合压缩对象指针与前面提到的堆内存限制的初始化的关系(涉及 JVM 参数:HeapBaseMinAddress,ObjectAlignmentInBytes,MinHeapSize,MaxHeapSize,InitialHeapSize
    7. 使用 jol + jhsdb + JVM 日志查看压缩对象指针与 Java 堆验证我们前面的结论
      1. 验证 32-bit 压缩指针模式
      2. 验证 Zero based 压缩指针模式
      3. 验证 Non-zero disjoint 压缩指针模式
      4. 验证 Non-zero based 压缩指针模式
    8. 堆大小的动态伸缩(涉及 JVM 参数:MinHeapFreeRatio,MaxHeapFreeRatio,MinHeapDeltaBytes)(全网最硬核 JVM 内存解析 - 6.其他 Java 堆内存相关的特殊机制开始)
    9. 适用于长期运行并且尽量将所有可用内存被堆使用的 JVM 参数 AggressiveHeap
    10. JVM 参数 AlwaysPreTouch 的作用
    11. JVM 参数 UseContainerSupport - JVM 如何感知到容器内存限制
    12. JVM 参数 SoftMaxHeapSize - 用于平滑迁移更耗内存的 GC 使用
  4. JVM 元空间设计(全网最硬核 JVM 内存解析 - 7.元空间存储的元数据开始)
    1. 什么是元数据,为什么需要元数据
    2. 什么时候用到元空间,元空间保存什么
      1. 什么时候用到元空间,以及释放时机
      2. 元空间保存什么
    3. 元空间的核心概念与设计(全网最硬核 JVM 内存解析 - 8.元空间的核心概念与设计开始)
      1. 元空间的整体配置以及相关参数(涉及 JVM 参数:MetaspaceSize,MaxMetaspaceSize,MinMetaspaceExpansion,MaxMetaspaceExpansion,MaxMetaspaceFreeRatio,MinMetaspaceFreeRatio,UseCompressedClassPointers,CompressedClassSpaceSize,CompressedClassSpaceBaseAddress,MetaspaceReclaimPolicy
      2. 元空间上下文 MetaspaceContext
      3. 虚拟内存空间节点列表 VirtualSpaceList
      4. 虚拟内存空间节点 VirtualSpaceNodeCompressedClassSpaceSize
      5. MetaChunk
        1. ChunkHeaderPool 池化 MetaChunk 对象
        2. ChunkManager 管理空闲的 MetaChunk
      6. 类加载的入口 SystemDictionary 与保留所有 ClassLoaderDataClassLoaderDataGraph
      7. 每个类加载器私有的 ClassLoaderData 以及 ClassLoaderMetaspace
      8. 管理正在使用的 MetaChunkMetaspaceArena
      9. 元空间内存分配流程(全网最硬核 JVM 内存解析 - 9.元空间内存分配流程开始)
        1. 类加载器到 MetaSpaceArena 的流程
        2. MetaChunkArena 普通分配 - 整体流程
        3. MetaChunkArena 普通分配 - FreeBlocks 回收老的 current chunk 与用于后续分配的流程
        4. MetaChunkArena 普通分配 - 尝试从 FreeBlocks 分配
        5. MetaChunkArena 普通分配 - 尝试扩容 current chunk
        6. MetaChunkArena 普通分配 - 从 ChunkManager 分配新的 MetaChunk
        7. MetaChunkArena 普通分配 - 从 ChunkManager 分配新的 MetaChunk - 从 VirtualSpaceList 申请新的 RootMetaChunk
        8. MetaChunkArena 普通分配 - 从 ChunkManager 分配新的 MetaChunk - 将 RootMetaChunk 切割成为需要的 MetaChunk
        9. MetaChunk 回收 - 不同情况下, MetaChunk 如何放入 FreeChunkListVector
      10. ClassLoaderData 回收
    4. 元空间分配与回收流程举例(全网最硬核 JVM 内存解析 - 10.元空间分配与回收流程举例开始)
      1. 首先类加载器 1 需要分配 1023 字节大小的内存,属于类空间
      2. 然后类加载器 1 还需要分配 1023 字节大小的内存,属于类空间
      3. 然后类加载器 1 需要分配 264 KB 大小的内存,属于类空间
      4. 然后类加载器 1 需要分配 2 MB 大小的内存,属于类空间
      5. 然后类加载器 1 需要分配 128KB 大小的内存,属于类空间
      6. 新来一个类加载器 2,需要分配 1023 Bytes 大小的内存,属于类空间
      7. 然后类加载器 1 被 GC 回收掉
      8. 然后类加载器 2 需要分配 1 MB 大小的内存,属于类空间
    5. 元空间大小限制与动态伸缩(全网最硬核 JVM 内存解析 - 11.元空间分配与回收流程举例开始)
      1. CommitLimiter 的限制元空间可以 commit 的内存大小以及限制元空间占用达到多少就开始尝试 GC
      2. 每次 GC 之后,也会尝试重新计算 _capacity_until_GC
    6. jcmd VM.metaspace 元空间说明、元空间相关 JVM 日志以及元空间 JFR 事件详解(全网最硬核 JVM 内存解析 - 12.元空间各种监控手段开始)
      1. jcmd <pid> VM.metaspace 元空间说明
      2. 元空间相关 JVM 日志
      3. 元空间 JFR 事件详解
        1. jdk.MetaspaceSummary 元空间定时统计事件
        2. jdk.MetaspaceAllocationFailure 元空间分配失败事件
        3. jdk.MetaspaceOOM 元空间 OOM 事件
        4. jdk.MetaspaceGCThreshold 元空间 GC 阈值变化事件
        5. jdk.MetaspaceChunkFreeListSummary 元空间 Chunk FreeList 统计事件
  5. JVM 线程内存设计(重点研究 Java 线程)(全网最硬核 JVM 内存解析 - 13.JVM 线程内存设计开始)
    1. JVM 中有哪几种线程,对应线程栈相关的参数是什么(涉及 JVM 参数:ThreadStackSize,VMThreadStackSize,CompilerThreadStackSize,StackYellowPages,StackRedPages,StackShadowPages,StackReservedPages,RestrictReservedStack
    2. Java 线程栈内存的结构
    3. Java 线程如何抛出的 StackOverflowError
      1. 解释执行与编译执行时候的判断(x86为例)
      2. 一个 Java 线程 Xss 最小能指定多大

3. Java 堆内存相关设计

3.1. 通用初始化与扩展流程

目前最新的 JVM,主要根据三个指标初始化堆以及扩展或缩小堆:

  • 最大堆大小
  • 最小堆大小
  • 初始堆大小

不同的 GC 情况下,初始化以及扩展的流程可能在某些细节不太一样,但是,大体的思路都是:

  1. 初始化阶段,reserve 最大堆大小,并且 commit 初始堆大小
  2. 在某些 GC 的某些阶段,根据上次 GC 的数据,动态扩展或者缩小堆大小,扩展就是 commit 更多,缩小就是 uncommit 一部分内存。但是,堆大小不会小于最小堆大小,也不会大于最大堆大小

3.2. 直接指定三个指标(MinHeapSize,MaxHeapSize,InitialHeapSize)的方式

这三个指标,直接对应的 JVM 参数是:

  • 最大堆大小MaxHeapSize,如果没有指定的话会有默认预设值用于指导 JVM 计算这些指标的大小,下一章节会详细分析,预设值为 125MB 左右(96M*13/10)
  • 最小堆大小MinHeapSize,默认为 0,0 代表让 JVM 自己计算,下一章节会详细分析
  • 初始堆大小InitialHeapSize,默认为 0,0 代表让 JVM 自己计算,下一章节会详细分析

对应源码是:https://github.com/openjdk/jdk/blob/jdk-21+3/src/hotspot/share/gc/shared/gc_globals.hpp

代码语言:javascript
复制
#define ScaleForWordSize(x) align_down((x) * 13 / 10, HeapWordSize)product(size_t, MaxHeapSize, ScaleForWordSize(96*M),                \"Maximum heap size (in bytes)")                                   \constraint(MaxHeapSizeConstraintFunc,AfterErgo)                   \
product(size_t, MinHeapSize, 0,                                     \"Minimum heap size (in bytes); zero means use ergonomics")        \constraint(MinHeapSizeConstraintFunc,AfterErgo)                   \
product(size_t, InitialHeapSize, 0,                                 \"Initial heap size (in bytes); zero means use ergonomics")        \constraint(InitialHeapSizeConstraintFunc,AfterErgo)               \

我们可以通过类似于 -XX:MaxHeapSize=1G 这种启动参数对这三个指标进行设置,但是,我们经常看到的可能是 Xmx 以及 Xms 这两个参数设置这三个指标,这两个参数分别对应:

  • Xmx:对应 最大堆大小 等价于 MaxHeapSize
  • Xms:相当于同时设置最小堆大小 MinHeapSize初始堆大小 InitialHeapSize

对应的 JVM 源码是:https://github.com/openjdk/jdk/blob/jdk-21+3/src/hotspot/share/runtime/arguments.cpp

代码语言:javascript
复制
//如果设置了 Xms
else if (match_option(option, "-Xms", &tail)) {julong size = 0;//解析 Xms 大小ArgsRange errcode = parse_memory_size(tail, &size, 0);if (errcode != arg_in_range) {jio_fprintf(defaultStream::error_stream(),"Invalid initial heap size: %s\n", option->optionString);describe_range_error(errcode);return JNI_EINVAL;}//将解析的值设置到 MinHeapSizeif (FLAG_SET_CMDLINE(MinHeapSize, (size_t)size) != JVMFlag::SUCCESS) {return JNI_EINVAL;}//将解析的值设置到 InitialHeapSizeif (FLAG_SET_CMDLINE(InitialHeapSize, (size_t)size) != JVMFlag::SUCCESS) {return JNI_EINVAL;}
//如果设置了 Xmx
} else if (match_option(option, "-Xmx", &tail) || match_option(option, "-XX:MaxHeapSize=", &tail)) {julong long_max_heap_size = 0;//解析 Xmx 大小ArgsRange errcode = parse_memory_size(tail, &long_max_heap_size, 1);if (errcode != arg_in_range) {jio_fprintf(defaultStream::error_stream(),"Invalid maximum heap size: %s\n", option->optionString);describe_range_error(errcode);return JNI_EINVAL;}//将解析的值设置到 MaxHeapSizeif (FLAG_SET_CMDLINE(MaxHeapSize, (size_t)long_max_heap_size) != JVMFlag::SUCCESS) {return JNI_EINVAL;}
}

最后提一句,JVM 启动参数,同一个参数可以多次出现,但是只有最后一个会生效,例如:

代码语言:javascript
复制
java -XX:MaxHeapSize=8G -XX:MaxHeapSize=4G -XX:MaxHeapSize=8M -version

这个命令启动的 JVM MaxHeapSize 为 8MB。由于前面提到 Xmx 与 MaxHeapSize 是等价的,所以这么写也是可以的(虽然最后 MaxHeapSize 还是 8MB):

代码语言:javascript
复制
java -Xmx=8G -XX:MaxHeapSize=4G -XX:MaxHeapSize=8M -version

3.3. 不手动指定三个指标的情况下,这三个指标(MinHeapSize,MaxHeapSize,InitialHeapSize)是如何计算的

上一章节我们提到我们可以手动指定这三个参数,如果不指定呢?JVM 会怎么计算这三个指标的大小?首先,当然,JVM 会读取 JVM 可用内存:首先 JVM 需要知道自己可用多少内存,我们称为可用内存。由此引入第一个 JVM 参数,MaxRAM,这个参数是用来明确指定 JVM 进程可用内存大小的,如果没有指定,JVM 会自己读取系统可用内存。这个可用内存用来指导 JVM 限制最大堆内存。后面我们会看到很多 JVM 参数与这个可用内存相关。

前面我们还提到了,就算没有指定 MaxHeapSize 或者 XmxMaxHeapSize 也有自己预设的一个参考值。源码中这个预设参考值为 125MB 左右(96M*13/10)。但是一般最后不会以这个参考值为准,JVM 初始化的时候会有很复杂的计算计算出合适的值。比如你可以在你的电脑上执行下下面的命令,可以看到类似下面的输出:

代码语言:javascript
复制
>  java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version|grep MaxHeapSizesize_t MaxHeapSize                              = 1572864000                                {product} {ergonomic}size_t SoftMaxHeapSize                          = 1572864000                             {manageable} {ergonomic}
openjdk version "17.0.2" 2022-01-18 LTS
OpenJDK Runtime Environment Corretto-17.0.2.8.1 (build 17.0.2+8-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.2.8.1 (build 17.0.2+8-LTS, mixed mode, sharing)

可以看到 MaxHeapSize 的大小,以及它的值是通过 ergonomic 决定的。也就是非人工指定而是 JVM 自己算出来的。

上面提到的那个 125MB 左右的初始参考值,一般用于 JVM 计算。我们接下来就会分析这个计算流程,首先是最大堆内存 MaxHeapSize 的计算流程:

image
image

流程中涉及了以下几个参数,还有一些已经过期的参数,会被转换成未过期的参数:

  • MinRAMPercentage:注意不要被名字迷惑,这个参数是在可用内存比较小的时候生效,即最大堆内存占用为可用内存的这个参数指定的百分比,默认为 50,即 50%
  • MaxRAMPercentage:注意不要被名字迷惑,这个参数是在可用内存比较大的时候生效,即最大堆内存占用为可用内存的这个参数指定的百分比,默认为 25,即 25%
  • ErgoHeapSizeLimit:通过自动计算,计算出的最大堆内存大小不超过这个参数指定的大小,默认为 0 即不限制
  • MinRAMFraction: 已过期,如果配置了会转化为 MinRAMPercentage 换算关系是:MinRAMPercentage = 100.0 / MinRAMFraction,默认是 2
  • MaxRAMFraction: 已过期,如果配置了会转化为 MaxRAMPercentage 换算关系是:MaxRAMPercentage = 100.0 / MaxRAMFraction,默认是 4

对应的源码是:https://github.com/openjdk/jdk/blob/jdk-21+3/src/hotspot/share/gc/shared/gc_globals.hpp

代码语言:javascript
复制
product(double, MinRAMPercentage, 50.0,                             \"Minimum percentage of real memory used for maximum heap"         \"size on systems with small physical memory size")                \range(0.0, 100.0)                                                 \
product(double, MaxRAMPercentage, 25.0,                             \"Maximum percentage of real memory used for maximum heap size")   \range(0.0, 100.0)                                                 \
product(size_t, ErgoHeapSizeLimit, 0,                               \"Maximum ergonomically set heap size (in bytes); zero means use " \"MaxRAM * MaxRAMPercentage / 100")                                \range(0, max_uintx)                                               \
product(uintx, MinRAMFraction, 2,                                   \"Minimum fraction (1/n) of real memory used for maximum heap "    \"size on systems with small physical memory size. "               \"Deprecated, use MinRAMPercentage instead")                       \range(1, max_uintx)                                               \
product(uintx, MaxRAMFraction, 4,                                   \"Maximum fraction (1/n) of real memory used for maximum heap "    \"size. "                                                          \"Deprecated, use MaxRAMPercentage instead")                       \range(1, max_uintx)                                               \

然后如果我们也没有设置 MinHeapSize 以及 InitialHeapSize,也会经过下面的计算过程计算出来:

image
image

流程中涉及了以下几个参数,还有一些已经过期的参数,会被转换成未过期的参数:

  • NewSize:初始新生代大小,预设值为 1.3MB 左右(1*13/10
  • OldSize:老年代大小,预设值为 5.2 MB 左右(4*13/10
  • InitialRAMPercentage:初始堆内存为可用内存的这个参数指定的百分比,默认为 1.5625,即 1.5625%
  • InitialRAMFraction: 已过期,如果配置了会转化为 InitialRAMPercentage 换算关系是:InitialRAMPercentage = 100.0 / InitialRAMFraction

对应的源码是:https://github.com/openjdk/jdk/blob/jdk-21+3/src/hotspot/share/gc/shared/gc_globals.hpp

代码语言:javascript
复制
product(size_t, NewSize, ScaleForWordSize(1*M),                     \"Initial new generation size (in bytes)")                         \constraint(NewSizeConstraintFunc,AfterErgo)                       \
product(size_t, OldSize, ScaleForWordSize(4*M),                     \"Initial tenured generation size (in bytes)")                     \range(0, max_uintx)                                               \
product(double, InitialRAMPercentage, 1.5625,                       \"Percentage of real memory used for initial heap size")           \range(0.0, 100.0)                                                 \
product(uintx, InitialRAMFraction, 64,                              \"Fraction (1/n) of real memory used for initial heap size. "      \"Deprecated, use InitialRAMPercentage instead")                   \range(1, max_uintx)                                               \

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转帖]System Performance 读书笔记 - 操作系统(1)

https://cloud.tencent.com/developer/article/1927381 本系列是针对 Systems Performance: Enterprise and the Cloud, 2nd Edition (2020) 书籍的读书笔记,加入了一些个人理解以及拓展,并且针对一些难以理解的地方提供了一些额外的参考内核(Kernel) 经典模型中,内核在操…

读人工智能时代与人类未来笔记05_现代人工智能

读人工智能时代与人类未来笔记05_现代人工智能1. 图灵 1.1. 1950年,数学家和逻辑学家艾伦图灵的论文《计算机与智能》中,图灵建议把机器智能的问题完全搁置 1.2. 图灵认为,重要的不是智能的机制,而是智能的表现 1.2.1. 因为其他生命的内在体验仍然是不可知的,所以我们衡量…

[转帖]为什么我建议需要定期重建数据量大但是性能关键的表

https://cloud.tencent.com/developer/article/1999970 个人创作公约:本人声明创作的所有文章皆为自己原创,如果有参考任何文章的地方,会标注出来,如果有疏漏,欢迎大家批判。如果大家发现网上有抄袭本文章的,欢迎举报,并且积极向这个 github 仓库 提交 issue,谢谢支持~…

尽微好物:从0到10亿+的抖音电商的TOP1“联盟团长”,如何使用NineData实现上云下云

杭州尽微供应链是抖⾳平台⽉均带货10E的TOP1“联盟团⻓”&#xff0c;是字节跳动⼀级代理商&#xff0c;巨量千川指定服务商&#xff0c;拥有商品库9万&#xff0c;是⾏业领先的电商供应链平台&#xff0c;达⼈陪跑机构。 杭州尽微供应链以天猫、京东抖音电商业务为依托&#x…

论文解读:Self-Promoted Supervision for Few-Shot Transformer

文章汇总 存在的问题 在没有归纳偏差的情况下&#xff0c;vit通常在只有少数标记训练数据可用的few-shot学习机制下学习低质量令牌依赖关系&#xff0c;这在很大程度上导致了上述性能下降。 动机 cnn的归纳偏置并不天生就适用于vit&#xff0c;也不能很好地增强和加速vit中…

Signal 即将成为JavaScript的一部分

什么是响应性&#xff1f; 在过去的几年中&#xff0c;响应性成为了所有现代前端框架以及React库的核心。 对于不熟悉前端开发的人来说&#xff0c;起初这可能是一个令人困惑的概念&#xff0c;因为它改变了常规的、自上而下的、从调用者到被调用者的顺序工作流。 在响应性范…

最近很火的粘土滤镜被玩坏了,教你用AI绘画SD免费无限制使用,附教程!

大家好&#xff0c;我是阿威。 最近在小红书上&#xff0c;“粘土特效”、“粘土滤镜”异常爆火&#xff0c;被网友玩出了花。 原来&#xff0c;一款海外修图工具——Remini&#xff08;类似妙鸭相机&#xff09;上线AI滤镜功能&#xff0c;其中就包括粘土滤镜&#xff0c;非常…

Adobe After Effects AE v24.3.0 解锁版 (视频合成及视频特效制作)

Adobe系列软件安装目录 一、Adobe Photoshop PS 25.6.0 解锁版 (最流行的图像设计软件) 二、Adobe Media Encoder ME v24.3.0 解锁版 (视频和音频编码渲染工具) 三、Adobe Premiere Pro v24.3.0 解锁版 (领先的视频编辑软件) 四、Adobe After Effects AE v24.3.0 解锁版 (视…

【线程创建】——三种方式➕多线程案例练习

02 线程创建 Thread , Runnable , Callable 三种创建方式 Thread class - 继承Thread类 (重点) Runnable接口 - 实现Runnable接口 (重点) Callable接口 - 实现Callable接口 (了解) Thread 类实现 它继承了老祖宗 Object java.lang.Object java.lang.Thread 它实现了 Runnab…

centOS忘记密码的处理办法

1、开机后在出现内核选项时&#xff0c;按 e&#xff1b; 2、在Linux 开头的这行&#xff0c;输入 rd.break 如下图&#xff1b; 3、然后&#xff0c;执行&#xff1a;CtrlX&#xff1b; 4、进入之后是 switch_root:/#输入 mount -o rw,remount /sysroot 以读写方式重新挂载 /s…

镊子蜡烛如何设置止盈止损?Anzo Capital昂首资本盈利收场

通过上一篇文章各位聪明的投资者&#xff0c;都已经知道了什么是镊子蜡烛图以及如何抓住反转进行交易&#xff0c;同时也有很多投资者不知道如何设置止盈止损&#xff1f;今天Anzo Capital昂首资本就和各位投资者一起探讨如何盈利收场。 看跌的镊子模式如何交易&#xff1f;首…

FFmpeg多张图片合成视频?

前言 商家在发布商品的时候&#xff0c;大部分情况下是没有视频的&#xff0c;这样往往会造成商品展示不全等问题&#xff0c;而视频制作又比较麻烦&#xff0c;为了解决此痛点&#xff0c;我们需要提供一键合成视频的功能。 之所以选择 FFmpeg&#xff0c;是因为我们期望后续…