内存碎片 Memory Fragmentation

本文深入探讨内存碎片的概念及其在嵌入式系统开发中的重要性。解释了内存碎片如何导致内存耗尽的问题,即使系统中仍有大量可用内存。文章还讨论了不同类型的内存碎片,包括内部碎片和外部碎片,以及编译时与运行时的内存分配差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Why Is Memory Fragmentation Important

In embedded systems development, memory fragmentation knowledge is crucial

Ultimately, memory fragmentation leads to out-of-memory conditions, even when there might be plenty of free memory left in the system.

  What Is Memory Fragmentation

Fragmented memory is the term used to describe all of a system's unusable free memory. These resources

remain unused, because the memory allocator that you are using is — for one reason or another — unable

to make this memory available to you.

  Compile Time vs. Run Time

Memory is allocated in many different contexts. The programmer can (by way of the compiler and linker)

allocate memory for data in structures, unions, arrays, and scalars as local, static, or global variables. The

programmer can also allocate memory dynamically in run time using calls such as malloc(). When the

compiler and linker perform the memory allocation function, memory fragmentation does not arise, because

the compiler understands the lifetime of the data. The data lifetime offers the nice advantage of being

stackable (last in, first out). This makes it possible for the memory allocator to work in a very efficient and

non-fragmenting manner. Generally, memory allocations issued during run time are not stackable. Memory

allocations are independent in time, which makes the problem extremely difficult to resolve.

Internal/ External Fragmentation and Overhead

Memory allocators waste memory in three basic ways:

• Overhead

• Internal fragmentation

• External fragmentation

The memory allocator needs to store some data describing the state of its allocations. That space is generally

called overhead. This is information about the location, size, and ownership of any free blocks and about

other internal states. A run-time allocator typically has no better place to store this overhead information

than in the memory it manages.

A memory allocator needs to adhere to some basic memory allocation rules. For example, all memory allocations

must start at an address that is divisible by 4, 8, or 16, depending on the processor architecture.

There may also be other reasons for the memory allocator to only assign blocks of certain predefined sizes

to its clients (cache-line size perhaps). When a client requests a block of 43 bytes, it may well get 44 or

48, or an even larger number. This extra space that results from rounding the requested size upwards is

called internal fragmentation.

External fragmentation is created when the memory allocator allocates blocks with unused gaps in between

them. This can occur, for example, when an application allocates three blocks in succession and then frees

the one in the middle. The memory allocator might reuse the middle block for future allocations, but it is

no longer possible to allocate a block as large as all free memory.

External fragmentation is created when the memory allocator allocates blocks with unused gaps in between
them. This can occur, for example, when an application allocates three blocks in succession and then frees
the one in the middle. The memory allocator might reuse the middle block for future allocations, but it is
no longer possible to allocate a block as large as all free memory.
Provided the memory allocator doesn't change its implementation or rounding policy in run time, the
overhead and internal fragmentation remains constant throughout an application's lifetime. While overhead
and internal fragmentation may be undesired (because they waste memory), external fragmentation is the
real enemy of embedded systems. External fragmentation is the allocation problem that kills systems.
Whenever the word fragmentation is used throughout the rest of this discussion, think external fragmentation

Definition

Now we are ready for a definition of (external) memory fragmentation. Other definitions are possible, but

this is the one most commonly used. It applies to external fragmentation, but can be modified to include

internal fragmentation (by including internal fragmentation in the denominator).

Figure 5.1 Definition of Memory Fragmentation


Fragmentation is a fraction between 0 and 1. A system in which fragmentation = 1 (100%) is completely

out of memory. With all free memory in a single block (the largest), fragmentation is 0%. With one quarter

of all free memory in the largest block, fragmentation is 75%. For example, fragmentation is 99% in a

system with 5 MB of free memory, when the largest block available for allocation is 50 KB.


内存碎片是一个很棘手的问题。如何分配内存决定着内存碎片是否会、何时会、如何会成为一个问题。

  即使在系统中事实上仍然有许多空闲内存时,内存碎片还会最终导致出现内存用完的情况。一个不断产生内存碎片的系统,不管产生的内存碎片多么小,只要时间足够长,就会将内存用完。这种情况在许多嵌入式系统中,特别是在高可用性系统中是不可接受的。有些软件环境,如 OSE 实时操作系统已经备有避免内存碎片的良好工具,但个别程序员做出的选择仍然会对最终结果形成影响。
  “碎片的内存”描述一个系统中所有不可用的空闲内存。这些资源之所以仍然未被使用,是因为负责分配内存的分配器使这些内存无法使用。这一问题通常都会发生,原因在于空闲内存以小而不连续方式出现在不同的位置。由于分配方法决定内存碎片是否是一个问题,因此内存分配器在保证空闲资源可用性方面扮演着重要的角色。

  编译时间与运行时间
  在许多情况下都会出现内存分配问题。程序员可以通过编译程序和链接程序,为结构、并集、数组和标量(用作局部变量、静态变量或全局变量)方面的数据分配内存,程序员还可以在运行时间使用诸如 malloc()调用命令动态地分配内存。当用编译程序和链接程序完成内存分配功能时,就不会出现内存碎片,因为编译程序了解数据寿命。掌握可供使用的数据寿命,好处在于可以使数据以后进先出的方式叠加起来。这样就可以使内存分配程序工作效率更高,而不会出现内存碎片。一般来说,运行时间内的内存分配是不可叠加的。内存分配在时间上是独立的,从而使得碎片问题难以解决。

图 1,内存碎片的几种形式。

内存分配程序浪费内存的基本方式有三种:即额外开销、内部碎片以及外部碎片(图 1)。内存分配程序需要存储一些描述其分配状态的数据。这些存储的信息包括任何一个空闲内存块的位置、大小和所有权,以及其它内部状态详情。一般来说,一个运行时间分配程序存放这些额外信息最好的地方是它管理的内存。内存分配程序需要遵循一些基本的内存分配规则。例如,所有的内存分配必须起始于可被 4、8 或 16 整除(视处理器体系结构而定)的地址。内存分配程序把仅仅预定大小的内存块分配给客户,可能还有其它原因。当某个客户请求一个 43 字节的内存块时,它可能会获得 44字节、48字节 甚至更多的字节。由所需大小四舍五入而产生的多余空间就叫内部碎片。
  外部碎片的产生是当已分配内存块之间出现未被使用的差额时,就会产生外部碎片。例如,一个应用程序分配三个连续的内存块,然后使中间的一个内存块空闲。内存分配程序可以重新使用中间内存块供将来进行分配,但不太可能分配的块正好与全部空闲内存一样大。倘若在运行期间,内存分配程序不改变其实现法与四舍五入策略,则额外开销和内部碎片在整个系统寿命期间保持不变。虽然额外开销和内部碎片会浪费内存,因此是不可取的,但外部碎片才是嵌入系统开发人员真正的敌人,造成系统失效的正是分配问题。
  定义内存碎片的方法有几种,其中最常用的是:

这一方法适用于外部碎片,但可以修改这一公式使之包括内部碎片,办法是把内部碎片加入到分母中。内存碎片是一个介于 0 和 1 之间的分数。一个碎片为 1(100%)的系统就是把内存全用完了。如果所有空闲内存都在一个内存块(最大内存块)中,碎片为 0%。当所有空闲内存的四分之一在最大内存块中时,碎片为 75%。例子如下:一个系统有 5M 字节的空闲内存,当它可用来分配的最大内存块为 50 k 字节时,其内存碎片为99%。这个 99%内存碎片实例来自开发嵌入式软实时系统期间出现的一种真实情况。当这种碎片程度发生一秒后,系统就崩溃了。该系统在碎片率达到 99% 之前,已经进行了约两周的连续现场测试。这种情况是如何发生的?为什么会发现得如此晚?当然,系统都经过测试,但测试很少超过两个小时。交付前的最后压力测试持续了一个周末。在这样短的测试周期内未必会产生内存碎片的后果,所以就发生了内存碎片需要多长时间才会达到临界值,这一问题很难回答。对某些应用来说,在某些情况下,系统会在用完内存前达到一种稳定状态。而对于另一些应用来说,系统则不会及时达到稳定状态(图 2)。只要消除不确定性因素和风险因素,不产生碎片的内存分配程序(图 3)就能快速达到一种稳定状态,从而有助于开发人员夜晚安稳睡觉。在开发数月甚至数年不再重新启动的长期运行系统时,快速收敛到稳定状态是一个重要因素。在比系统连续运行周期短的时间内,对系统进行适当的测试,这是必不可少的。
图 2,这一案例研究把最先适合内存分配程序用于一个嵌入系统项目。系统在现场测试中连续运行了两周,然后碎片率达到 99%。
图 3,一个不产生碎片的内存分配程序一旦试验应用程序的全部,它就能达到稳定状态。


  很难确定哪种内存分配算法更胜一筹,因为每种算法在不同的应用中各有所长(表 1)。最先适合内存分配算法是最常用的一种。它使用了四个指针:MSTART 指向被管理内存的始端;MEND 指向被管理内存的末尾;MBREAK 指向 MSTART 和 MEND 之间已用内存的末端; PFREE 则指向第一个空闲内存块(如果有的话)。

在系统开始运行时,PFREE 为 NULL,MBREAK 指向 MSTART。当一个分配请求来到时,分配程序首先检查 PFREE有无空闲内存块。由于 PFREE 为 NULL,一个具有所请求存储量加上管理标题的内存块就脱离 MBREAK ,然后MBREAK就更新。这一过程反复进行,直至系统使一个内存块空闲,管理标题包含有该存储块的存储量为止。此时,PFREE 通过头上的链接表插入项被更新为指向该内存块,而块本身则用一个指向旧 PFREE 内容的指针进行更新,以建立一个链接表。下一次出现分配请求时,系统就会搜索空闲内存块链接表,寻找适合请求存储量的第一个空闲内存块。一旦找到合适的内存块,它将此内存块分成两部分,一部分返还给系统,另一部分则送回给自由表。
  最先适合内存分配算法实现起来简单,而且开始时很好用。但是,经过一段时间后,会出现如下的情况:当系统将内存交给自由表时,它会从自由表的开头部分去掉大内存块,插入剩余的小内存块。最先适合算法实际上成了一个排序算法,即把所有小内存碎片放在自由表的开头部分。因此,自由表会变得很长,有几百甚至几千个元素。因此,内存分配变得时间很长又无法预测,大内存块分配所花时间要比小内存块分配来得长。另外,内存块的无限制拆分使内存碎片程度很高。有些实现方法在使内存空闲时会将邻近的空闲内存块连接起来。这种方法多少有些作用,而最先适合算法与时间共处算法(time co-location)和空间共处算法(spatial co-location)不同,它在使内存块空闲时,无法提高相邻内存块同时空闲的概率。

  最佳适合与最差适合分配程序
  最佳适合算法在功能上与最先适合算法类似,不同之处是,系统在分配一个内存块时,要搜索整个自由表,寻找最接近请求存储量的内存块。这种搜索所花的时间要比最先适合算法长得多,但不存在分配大小内存块所需时间的差异。最佳适合算法产生的内存碎片要比最先适合算法多,因为将小而不能使用的碎片放在自由表开头部分的排序趋势更为强烈。由于这一消极因素,最佳适合算法几乎从来没有人采用过。
  最差适合算法也很少采用。最差适合算法的功能与最佳适合算法相同,不同之处是,当分配一个内存块时,系统在整个自由表中搜索与请求存储量不匹配的内存快。这种方法比最佳适合算法速度快,因为它产生微小而又不能使用的内存碎片的倾向较弱。始终选择最大空闲内存块,再将其分为小内存块,这样就能提高剩余部分大得足以供系统使用的概率。
  伙伴(buddy)分配程序与本文描述的其它分配程序不同,它不能根据需要从被管理内存的开头部分创建新内存。它有明确的共性,就是各个内存块可分可合,但不是任意的分与合。每个块都有个朋友,或叫“伙伴”,既可与之分开,又可与之结合。伙伴分配程序把内存块存放在比链接表更先进的数据结构中。这些结构常常是桶型、树型和堆型的组合或变种。一般来说,伙伴分配程序的工作方式是难以描述的,因为这种技术随所选数据结构的不同而各异。由于有各种各样的具有已知特性的数据结构可供使用,所以伙伴分配程序得到广泛应用。有些伙伴分配程序甚至用在源码中。伙伴分配程序编写起来常常很复杂,其性能可能各不相同。伙伴分配程序通常在某种程度上限制内存碎片。
  固定存储量分配程序有点像最先空闲算法。通常有一个以上的自由表,而且更重要的是,同一自由表中的所有内存块的存储量都相同。至少有四个指针:MSTART 指向被管理内存的起点,MEND 指向被管理内存的末端,MBREAK 指向 MSTART 与 MEND 之间已用内存的末端,而 PFREE[n] 则是指向任何空闲内存块的一排指针。在开始时,PFREE[*] 为 NULL,MBREAK 指针为 MSTART。当一个分配请求到来时,系统将请求的存储量增加到可用存储量之一。然后,系统检查 PFREE[ 增大后的存储量 ] 空闲内存块。因为 PFREE[ 增大后的存储量 ] 为 NULL,一个具有该存储量加上一个管理标题的内存块就脱离 MBREAK,MBREAK 被更新。
  这些步骤反复进行,直至系统使一个内存块空闲为止,此时管理标题包含有该内存块的存储量。当有一内存块空闲时,PFREE[ 相应存储量 ] 通过标题的链接表插入项更新为指向该内存块,而该内存块本身则用一个指向 PFREE[ 相应存储量 ] 以前内容的指针来更新,以建立一个链接表。下一次分配请求到来时,系统将 PFREE[ 增大的请求存储量 ] 链接表的第一个内存块送给系统。没有理由搜索链接表,因为所有链接的内存块的存储量都是相同的。
  固定存储量分配程序很容易实现,而且便于计算内存碎片,至少在块存储量的数量较少时是这样。但这种分配程序的局限性在于要有一个它可以分配的最大存储量。固定存储量分配程序速度快,并可在任何状况下保持速度。这些分配程序可能会产生大量的内部内存碎片,但对某些系统而言,它们的优点会超过缺点。

  减少内存碎片
  内存碎片是因为在分配一个内存块后,使之空闲,但不将空闲内存归还给最大内存块而产生的。最后这一步很关键。如果内存分配程序是有效的,就不能阻止系统分配内存块并使之空闲。即使一个内存分配程序不能保证返回的内存能与最大内存块相连接(这种方法可以彻底避免内存碎片问题),但你可以设法控制并限制内存碎片。所有这些作法涉及到内存块的分割。每当系统减少被分割内存块的数量,确保被分割内存块尽可能大时,你就会有所改进。
  这样做的目的是尽可能多次反复使用内存块,而不要每次都对内存块进行分割,以正好符合请求的存储量。分割内存块会产生大量的小内存碎片,犹如一堆散沙。以后很难把这些散沙与其余内存结合起来。比较好的办法是让每个内存块中都留有一些未用的字节。留有多少字节应看系统要在多大程度上避免内存碎片。对小型系统来说,增加几个字节的内部碎片是朝正确方向迈出的一步。当系统请求1字节内存时,你分配的存储量取决于系统的工作状态。
  如果系统分配的内存存储量的主要部分是 1 ~ 16 字节,则为小内存也分配 16 字节是明智的。只要限制可以分配的最大内存块,你就能够获得较大的节约效果。但是,这种方法的缺点是,系统会不断地尝试分配大于极限的内存块,这使系统可能会停止工作。减少最大和最小内存块存储量之间内存存储量的数量也是有用的。采用按对数增大的内存块存储量可以避免大量的碎片。例如,每个存储量可能都比前一个存储量大 20%。在嵌入式系统中采用“一种存储量符合所有需要”对于嵌入式系统中的内存分配程序来说可能是不切实际的。这种方法从内部碎片来看是代价极高的,但系统可以彻底避免外部碎片,达到支持的最大存储量。
  将相邻空闲内存块连接起来是一种可以显著减少内存碎片的技术。如果没有这一方法,某些分配算法(如最先适合算法)将根本无法工作。然而,效果是有限的,将邻近内存块连接起来只能缓解由于分配算法引起的问题,而无法解决根本问题。而且,当内存块存储量有限时,相邻内存块连接可能很难实现。
  有些内存分配器很先进,可以在运行时收集有关某个系统的分配习惯的统计数据,然后,按存储量将所有的内存分配进行分类,例如分为小、中和大三类。系统将每次分配指向被管理内存的一个区域,因为该区域包括这样的内存块存储量。较小存储量是根据较大存储量分配的。这种方案是最先适合算法和一组有限的固定存储量算法的一种有趣的混合,但不是实时的。
  有效地利用暂时的局限性通常是很困难的,但值得一提的是,在内存中暂时扩展共处一地的分配程序更容易产生内存碎片。尽管其它技术可以减轻这一问题,但限制不同存储量内存块的数目仍是减少内存碎片的主要方法。
  现代软件环境业已实现各种避免内存碎片的工具。例如,专为分布式高可用性容错系统开发的 OSE 实时操作系统可提供三种运行时内存分配程序:内核 alloc(),它根据系统或内存块池来分配;堆 malloc(),根据程序堆来分配; OSE 内存管理程序 alloc_region,它根据内存管理程序内存来分配。
  从 许多方面来看,Alloc就是终极内存分配程序。它产生的内存碎片很少,速度很快,并有判定功能。你可以调整甚至去掉内存碎片。只是在分配一个存储量后,使之空闲,但不再分配时,才会产生外部碎片。内部碎片会不断产生,但对某个给定的系统和八种存储量来说是恒定不变的。
  Alloc 是一种有八个自由表的固定存储量内存分配程序的实现方法。系统程序员可以对每一种存储量进行配置,并可决定采用更少的存储量来进一步减少碎片。除开始时以外,分配内存块和使内存块空闲都是恒定时间操作。首先,系统必须对请求的存储量四舍五入到下一个可用存储量。就八种存储量而言,这一目标可用三个 如果 语句来实现。其次,系统总是在八个自由表的表头插入或删除内存块。开始时,分配未使用的内存要多花几个周期的时间,但速度仍然极快,而且所花时间恒定不变。
  堆 malloc() 的内存开销(8 ~ 16 字节/分配)比 alloc小,所以你可以停用内存的专用权。malloc() 分配程序平均来讲是相当快的。它的内部碎片比alloc()少,但外部碎片则比alloc()多。它有一个最大分配存储量,但对大多数系统来说,这一极限值足够大。可选的共享所有权与低开销使 malloc() 适用于有许多小型对象和共享对象的 C++ 应用程序。堆是一种具有内部堆数据结构的伙伴系统的实现方法。在 OSE 中,有 28 个不同的存储量可供使用,每种存储量都是前两种存储量之和,于是形成一个斐波那契(Fibonacci)序列。实际内存块存储量为序列数乘以 16 字节,其中包括分配程序开销或者 8 字节/分配(在文件和行信息启用的情况下为 16 字节)。
  当你很少需要大块内存时,则OSE内存管理程序最适用。典型的系统要把存储空间分配给整个系统、堆或库。在有 MMU 的系统中,有些实现方法使用 MMU 的转换功能来显著降低甚至消除内存碎片。在其他情况下,OSE 内存管理程序会产生非常多的碎片。它没有最大分配存储量,而且是一种最先适合内存分配程序的实现方法。内存分配被四舍五入到页面的偶数——典型值是 4 k 字节。(T111)


<think>好的,我现在需要帮助用户解答关于Redis内存碎片查看方法以及used_memory_overhead具体含义的问题。首先,我需要回顾用户之前的提问和我的回答,确保信息的一致性。 用户之前询问了used_memory_overhead的占用情况,我解释了其定义、组成结构、验证方法和优化建议。现在用户进一步想了解如何查看内存碎片以及used_memory_overhead的具体组成,同时引用了三个相关的资料片段。 首先,确定用户的需求:他们希望了解如何查看Redis的内存碎片率,以及used_memory_overhead包含哪些内容。需要结合之前的回答和引用资料来提供准确的步骤和解释。 查看内存碎片率的方法,根据引用[2]和[3],可以通过`info memory`命令获取mem_fragmentation_ratio,这个指标是used_memory_rss与used_memory的比值。需要详细说明每个参数的意义,并给出示例,如引用[3]中的输出,解释碎片率的计算方法。 关于used_memory_overhead的组成,我之前已经分点列出了内部数据结构、客户端资源、复制缓冲等。需要再次强调这些组成部分,并结合引用[1]中提到的内存碎片清理问题,说明used_memory_overhead可能包含内存碎片,以及如何通过`memory purge`或重启来优化。 需要注意的是,用户可能对如何具体操作和解读命令结果有疑问,因此需要分步骤说明命令的使用和输出中的关键字段。同时,要给出优化建议,如调整配置参数、限制客户端缓冲区、处理碎片等,引用之前的建议和用户提供的资料中的方法。 还要检查是否有遗漏的信息,例如引用[3]中的具体info memory输出,是否需要在回答中展示示例,帮助用户更直观地理解。此外,确保回答结构清晰,分点列出查看方法和组成结构,并附带相关问题的建议,保持与之前回答的一致性。 最后,确保语言简洁明了,避免技术术语过于复杂,同时保持专业性。验证所有信息是否正确,尤其是数值和命令的正确性,避免误导用户。比如,内存碎片率的计算公式是否正确,used_memory_overhead的组成部分是否有遗漏等。 总结来说,回答需要分为两部分:内存碎片的查看方法和used_memory_overhead的组成。每部分都需要步骤说明、命令示例、关键指标解释,并结合引用资料中的信息进行补充。最后给出优化建议和相关问题,帮助用户进一步解决问题。</think>### 一、Redis内存碎片的查看方法 #### 1. 核心指标与计算公式 内存碎片率通过以下公式计算(引用自[^2][^3]): $$mem\_fragmentation\_ratio = \frac{used\_memory\_rss}{used\_memory}$$ - **$used\_memory$**:Redis分配器实际申请的内存(通过`jemalloc`等分配器管理) - **$used\_memory\_rss$**:操作系统视角下Redis进程占用的物理内存 - **$mem\_fragmentation\_ratio$**:若该值 **>1.5** 表示存在显著内存碎片,**<1** 表示内存被压缩(如启用了`jemalloc`的透明大页) #### 2. 查看步骤 通过`redis-cli`执行以下命令查看详细内存分布: ```bash > info memory # 查看所有内存指标 > info memory | grep "mem_fragmentation_ratio" # 直接筛选碎片率 ``` 示例输出(引用自[^3]): ```plaintext mem_fragmentation_ratio:1.54 # 表示54%的内存碎片 used_memory:1073741736 # 数据内存+管理内存(单位字节) used_memory_rss:1650737152 # 操作系统视角的实际占用 ``` #### 3. 碎片率解读 | 碎片率范围 | 状态说明 | 处理建议 | |----------------|----------------------------|---------------------------| | 1.0~1.1 | 理想状态 | 无需操作 | | 1.1~1.5 | 可控范围 | 监控观察 | | **>1.5** | 高碎片率(如示例中的1.54) | 需执行内存清理或重启实例 | | <1.0 | 内存压缩(Swap风险) | 检查是否开启透明大页 | --- ### 二、`used_memory_overhead`的具体含义与组成 #### 1. 定义公式 $$used\_memory\_overhead = used\_memory - used\_memory\_dataset$$ 该指标表示Redis为维护数据存储和运行所需的管理性内存开销(引用自[^1][^3])。 #### 2. 核心组成部分 | 组成部分 | 说明 | 典型场景示例 | |----------------------|--------------------------------------------------------------------|---------------------------| | **全局哈希表** | 存储所有Key的元信息(每个Key约$104B$) | 10万Key占用约$10MB$ | | **客户端缓冲区** | 每个客户端连接默认分配输入/输出缓冲区(`client-output-buffer-limit`控制) | 1000连接占用约$64MB$ | | **复制缓冲区** | 主节点为每个从节点维护的$1MB$复制积压缓冲区(`repl-backlog-size`可调) | 10从节点占用$10MB$ | | **Lua脚本缓存** | 存储已执行但未释放的Lua脚本 | 大脚本可能占用数十MB | | **持久化缓冲区** | RDB/AOF生成时的临时内存占用 | AOF重写期间显著增加 | | **内存碎片** | 分配器未能有效利用的内存间隙(如大量删除Key后产生) | 碎片率>1.5时需主动清理[^1] | --- ### 三、优化建议 1. **内存碎片清理** - 执行`memory purge`强制释放碎片(依赖`jemalloc`支持)[^1] - 重启实例(极端情况下) 2. **控制`used_memory_overhead`** - 通过`hash-max-ziplist-entries`优化小对象存储编码 - 限制客户端缓冲区:`config set client-output-buffer-limit "normal 256mb 128mb 60"` - 减少冗余Key:定期清理过期或无用Key --- ### 四、操作验证示例 1. 查看内存分布详情: ```bash > MEMORY STATS # 输出包含数据集内存、管理内存碎片率等 ``` 2. 主动清理碎片(需Redis 4.0+): ```bash > memory purge # 触发jemalloc内存整理 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值