深入浅出:Python内存管理机制详解

这篇具有很好参考价值的文章主要介绍了深入浅出:Python内存管理机制详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、什么是内存?

1.1、RAM简介

随机存取存储器(Random Access Memory,RAM):是计算机中用于临时存储数据的一种硬件组件。它是计算机的主要内存之一,用于存储正在运行的程序和操作系统所需的数据。

主要特点:

  • 临时存储:RAM 存储的数据是临时的,意味着当计算机关闭或重启时,其中的数据会被清空。这与永久存储设备(如硬盘驱动器)不同,后者可以长期保存数据。
  • 随机存取:RAM 具备随机访问能力,这意味着它可以快速访问存储中的任何数据,而无需按照特定的顺序来读取。这使得 RAM 非常适合用作计算机的工作内存,以快速存取和处理数据。
  • 高速存储:RAM 是一种高速存储设备,数据可以在毫秒或甚至纳秒级别的时间内被读取或写入。这使得计算机能够快速执行任务,提高性能。
  • 容量较小:RAM 的容量通常相对较小,通常以兆字节(MB)或千兆字节(GB)来衡量。计算机的 RAM 容量会影响其多任务处理能力和运行大型程序的性能。

1.2、RAM容量

RAM的容量:表示计算机(当前 / 单次)能够同时加载和计算的数据和程序的总内存上限例如:当前计算机具有64GB的RAM,那么可以在同一时刻加载和运行的数据和程序总共不能超过64GB。否则将导致(RAM)内存不足,并且可能会导致系统变得非常慢甚至系统崩溃。

内存的使用:

  • 操作系统:操作系统需要占用一部分RAM,以便运行系统的核心功能。
  • 正在运行的应用程序:每个打开的应用程序需要分配一部分RAM,以存储其数据和代码。更大的应用程序和多任务处理可能需要更多的RAM。
  • 正在处理的数据:如打开的文档、图像、视频或音频文件,都需要RAM来存储。
  • 缓存和临时数据:操作系统和应用程序通常使用RAM来加速数据的读取和写入,因此一些RAM也会被用于缓存和临时存储。
    当超过RAM容量的数据和程序被加载时,计算机性能会受到影响,因为它将不得不频繁地从硬盘或固态硬盘等永久存储设备中读取数据,这通常较慢,导致性能下降。

1.3、查看电脑内存

python 如何进行内存管理,深度学习,Python项目实战,python,内存管理,内存优化

1.4、监控电脑内存

当前内存的使用情况
python 如何进行内存管理,深度学习,Python项目实战,python,内存管理,内存优化

当前内存的使用占比
python 如何进行内存管理,深度学习,Python项目实战,python,内存管理,内存优化

二、RAM是CPU的主内存,显存是GPU的专用内存

RAM(随机存取存储器)是中央处理器CPU的主内存:用于临时存储正在运行的程序和操作系统使用的数据。它是一种易失性存储器,意味着当计算机关闭时,其中存储的数据会丢失。

  • 功能:CPU通过RAM读取数据和指令来支持计算机运行时的各种任务。
  • 性能:RAM的速度和容量对CPU的性能至关重要。较大且更快的RAM能够更有效地提供所需的数据,从而减少CPU等待数据的时间。

显存(Graphics RAM)是图形处理器GPU的专用内存:用于存储图形数据,如纹理、帧缓冲区、深度缓冲区等。

  • 功能:显存是GPU专用的高速内存,为了提供快速访问和高带宽而优化的。
  • 性能:显存的大小和类型(例如GDDR5、GDDR6等)直接影响了GPU处理大规模图形数据的能力。更大容量和更高带宽的显存通常意味着GPU能够处理更复杂的图形任务。
  • CPU(中央处理器):计算机系统的核心,负责执行系统任务,包括控制计算机的运行、执行算术和逻辑操作、管理系统资源等。CPU具有较少的核心(几个到数十个),适用于通用计算。
  • GPU(图形处理器):最初是为图形渲染而设计的,但由于其并行处理能力,它在科学计算、深度学习等领域也得到广泛应用。GPU具有大量的小型处理核心,适用于大规模并行计算。

协同工作:在深度学习中,CPU负责管理任务和调度工作,而GPU用于加速大规模矩阵运算,提高训练速度。

三、内存管理

3.0、不同数据类型的内存范围

在计算机内存中,图像内存的计算公式:内存大小 = 宽度 × 高度 × 通道数 x 每个像素的字节数内存的基本存储单元是字节而不是位,且是整数表示。

# 在计算机中,最小的存储单元是位(bit),而一个字节(Byte)通常由8个位组成。

1 TB = 1024 GB = [1024^2] MB = [1024^3] KB = [1024^4] Bytes = [1024^4 x 8] bits
位(bits) + 字节(Bytes) + 千字节(Kilobytes,KB) + 兆字节(Megabytes,MB) + 吉字节(Gigabytes,GB) + 千兆字节(Terabytes,TB) + PB + EB + ZB + YB
数据类型 说明 每个像素的字节数 数据范围 内存范围
bool 布尔类型 1位 [0,1] 2bits
int8 有符号8位整数 8位(1字节) [-128,127] [-16,16]Bytes
uint8 无符号8位整数 8位(1字节) [0,255] [0,32]Bytes
int16 有符号16位整数 16位(2字节) [-32768,32767] [-32,32]KB
uint16 无符号16位整数 16位(2字节) [0,65535] [0,64]KB
int32 有符号32位整数 32位(4字节) [-2,147,483,648,2,147,483,647] [-2,2]GB
uint32 无符号32位整数 32位(4字节) [0,4,294,967,295] [0,4]GB
int64 有符号64位整数 64位(8字节) [-9.22×1018,9.22×1018] [-8,8]EB
uint64 无符号64位整数 64位(8字节) [0,18,446,744,073,709,551,615] [0,16]EB

3.1、python是如何分配内存的?

Python内存管理器如何分配内存:根据对象的大小选择一块足够大的内存块,且将这块内存划分为两个部分,一个用于存储对象的数据,另一个用于存储对象的引用。
(1)在Python中,使用对象时自动分配内存,并当不再使用对象时自动释放内存。
(2)在Python中,对象都是动态类型(即声明变量时不需要指定数据类型,python会自动确定),且都是动态内存分配。

3.2、python采用自动内存管理机制

Python通过" 引用计数 “和” 循环引用检测 "来自动管理内存(即垃圾回收器)。因此在一般情况下,程序员不需要过多关注内存释放。只有在处理大型数据集或需要及时回收内存的特殊情况下,才需要考虑手动内存管理。

自动内存管理机制:又叫垃圾回收器(garbage collector,gc)负责定期地扫描并自动回收不再使用的内存和对象,使得开发者可以专注于程序逻辑,而不必担心内存管理问题。
(1)垃圾回收器:具体释放时机由解释器内部的策略控制,而不是由程序员明确控制的。
(2)垃圾回收器:不是严格按照预定的周期运行的,而是按照分代算法进行回收。

垃圾回收器的触发因素:

  • (1)手动垃圾回收采用gc.collect()进行手动强制执行垃圾回收,用来解决在内存敏感时(例如:内存不足)加速释放不再需要的内存
    • 1、Python采用自动垃圾回收机制,在后台定期自动检测不再被引用的对象并释放它们的内存。自动垃圾回收与gc.collect()相比,其会有一个等待期(定期检测)。
    • 2、在一般情况下,不需要手动使用 gc.collect(),因为Python的垃圾回收机制通常是足够智能的,会在合适的时候自动运行以释放不再需要的内存。
    • 3、gc.collect()是加速自动垃圾回收的执行速度,而不是立即释放内存(但也几乎等同)。
    • 4、gc.collect()本身也会引起额外的开销,故不建议频繁触发手动垃圾回收。
  • (2)引用计数(reference count)垃圾回收机制会记录每个对象被其他对象所引用的次数
    • 1、引用计数从0开始;
    • 2、当对象有新的引用指向它时,则引用次数 +1;当该对象指向它的引用失效时(如:del 对象),则引用 -1。
    • 3、当对象的引用计数为0时(如:对象=None),则列入垃圾回收队列,等待自动垃圾回收,而不是立即释放内存。
      • 【del 对象】: 使用del语句将对象从命名空间中删除,内存将被立即释放,但Python的内存池机制导致不会立即释放内存给计算机,而是等待复用。
      • 【对象=None】: 将对象设置为None,该对象的引用计数变为零,但不会立即释放,而是等待自动垃圾回收机制进行内存释放。
  • (3)循环引用检测若对象之间存在相互引用,则对象间将形成一个环状结构,使得引用计数不会降为零,因此内存无法被自动回收,导致内存泄漏。 分代回收
    • 1、引用链:用于跟踪对象之间的引用关系。当引用计数不为零,但对象之间形成循环引用时。
    • 2、分代回收(generation)将所有对象分为0,1,2三代。所有新创建的对象都是第0代对象;当某一代对象经过垃圾回收后仍然存活,就会升级到下一代。
      • 11、垃圾回收启动时,一定会扫描所有的0代对象。
      • 22、如果0代经过一定次数垃圾回收,那么就启动对0代和1代的扫描清理。
      • 33、当1代也经历了一定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进行扫描。
  • (4)内存池用于提高小内存对象的内存分配和释放效率。若频繁的进行小内存对象的分配和释放,可能导致内存碎片化和性能下降。
    • 1、预分配固定大小的内存块:Python会根据对象的大小选择一个合适的内存块。每个内存块包含多个相同大小的小块。通常以8字节为一块。
    • 2、内存块状态:内存块可以有不同的状态,包括空闲、已分配和已释放。Python会维护内存块的状态。
    • 2、对象复用:如果内存块中包含已释放的小块,Python会首先复用这些小块以减少内存分配开销。这意味着相同大小的内存块可以多次分配和释放,而不需要每次都与操作系统进行交互。
    • 3、延迟释放:对于不再使用的内存块不会立即释放回操作系统,而是将其保留在内存池中,以备将来再次使用(对象复用)。
      优点有助于减少频繁的内存分配和释放带来的性能开销。
      缺点可能导致内存泄漏,因为不再使用的内存块不会立即被操作系统回收。因此,开发者应避免长期保留对不再使用的对象的引用,以避免内存泄漏。

内存池机制(类别于金字塔模型): 图形化理解内存池
python 如何进行内存管理,深度学习,Python项目实战,python,内存管理,内存优化

  • 第-1层,第-2层:由操作系统特定的虚拟内存管理器控制(OS-specific virtual memory manger(VMM))
    (第 -1 层):内核动态存储分配和管理
    (第 -2 层):物理内存(ROM / RAM) + 二级存储

    • ROM(只读存储器,Read-Only Memory):用于存储计算机或其他电子设备的固件和固定数据的存储设备。常用于存储计算机的引导程序(BIOS)。与RAM不同,ROM中的数据通常无法被修改。
    • RAM(随机访问存储器,Random Access Memory):用于存储正在运行的程序和数据的临时内存存储设备。常用于计算机快速读取和写入数据。RAM是易失性的,断电时数据会丢失。
    • 二级存储(交换,Secondary Storage):指非易失性的大容量存储设备,如硬盘驱动器(HDD)或固态驱动器(SSD)。它用于长期存储数据、文件和操作系统。与RAM不同,二级存储的数据在断电时不会丢失。
  • 第0层:由C标准库中底层分配器(underlying general-purpose allocator)的malloc、free进行内存分配和内存释放;

  • 第1层当申请的内存 >256KB 时,内存分配由 Python 原生的内存分配器(raw memory allocator)进行分配,本质上是调用C标准库中的malloc、realloc等函数。

  • 第2层当申请的内存 <256KB 时,内存分配由 Python 对象分配器(object allocator)实施。

  • 第3层:用户使用对象的直接操作层。特点:对于python内置对象(如:int、dict、list、string等),每个数据类型都有独立的私有内存池,对象之间的内存池不共享。如:int释放的内存,不会被分配给float使用。

3.3、python自动内存管理机制的缺点

  • (1)内存泄漏程序在分配内存后,无法正常释放不再使用的内存。最终可能导致程序运行变得缓慢或崩溃。 常见的几种情况如下:
    • 如果程序分配了内存,但未在不再需要时释放它,内存将泄漏。
    • 如果数据结构设计不正确,可能在不再需要时保留对对象的引用,导致内存泄漏。
    • 如果循环引用或不正确的引用计数,可能发生内存泄漏。
    • 如果打开文件却未在使用后正确关闭它们,内存将泄漏。
  • (2)性能下降:需要同时分配与释放内存,程序可能会变慢。
  • (3)内存不足:当程序需要的内存大于系统空间的内存,则会出现内存不足的问题。

3.4、python内存优化的方法

【python如何优化内存1】 + 【python如何优化内存2】文章来源地址https://www.toymoban.com/news/detail-757535.html

  • 降低全局变量的使用率:全局变量会一直存在到程序结束,因此会始终占用内存。若非必要,请尽可能地使用局部变量,并在不需要时尽快将其释放。
  • 避免创建非必要的对象:在Python中,创建对象是分配内存的一种方式。因此,尽量避免创建不必要的对象,并通过复用对象的方式来减少内存分配的次数。
  • 手动释放非必要的对象采用gc.collect()进行手动强制执行垃圾回收,用来在内存敏感时(例如:内存不足)立即释放不再需要的内存

四、项目实战

4.1、查看对象的引用计数

import sys

def create_objects():
    obj1 = [1, 2, 3]			    # 创建对象      (obj1对象的引用次数=2)
    obj2 = [obj1, 1]		        # 创建对象      (obj2对象的引用次数=1)
    obj3 = {'a': 1, 'b': 2}		    # 创建对象      (obj3对象的引用次数=1)
    print(sys.getrefcount(obj1))  # 获取对象a的引用次数
    print(sys.getrefcount(obj2))  # 获取对象a的引用次数
    print(sys.getrefcount(obj3))  # 获取对象a的引用次数
    #########################################################################
    obj1 = None  		# 将不再使用对象的引用设置为None     (obj2对象的引用次数=0)
    del obj2  		    # 将不再使用对象的引用设置为None     (obj1对象的引用次数=0)
    print(sys.getrefcount(obj1))  # 获取对象a的引用次数
    print(sys.getrefcount(obj3))  # 获取对象a的引用次数
    return

create_objects()  # 创建对象

"""###################################################################
# 函数:sys.getrefcount(a): 返回对象a的引用计数。
# 注意: 函数内部会增加一次临时引用计数来获取对象的引用数,但该函数执行之后会自动减去临时引用计数,以保持对象的引用计数不变。
# 
# 【del 对象】:	(1)使用del语句将对象从命名空间中删除,该对象的内存将被立即释放;
# 				(2)但Python的内存池机制导致该部分占用的内存不会立即释放给计算机,而是等待复用。
# 【对象=None】:	(1)将对象设置为None,该对象的引用计数变为零;
# 				(2)但内存不会立即释放,而是等待自动垃圾回收机制进行内存释放。
###################################################################"""

4.2、内存池:设置垃圾回收的第 i 代阈值

import gc
gc.set_threshold(700, 10, 5)

"""###################################################################
# 函数功能:设置垃圾回收的第i代阈值。
# 函数简介:gc.set_threshold(threshold0, threshold1, threshold2)
# 输入参数:    
#            threshold0      是垃圾回收的第0代阈值。当0代的垃圾数量达到这个值时,触发0代的垃圾回收。
#            threshold1      是垃圾回收的第1代阈值。当0代的垃圾数量达到 threshold0,且0和1两代垃圾的总数达到 threshold1,则触发两代的垃圾回收。
#            threshold2      是垃圾回收的第2代阈值。当0和1两代垃圾的总数达到 threshold1,且同时0/1/2三代垃圾的总数达到 threshold2,则触发三代的垃圾回收。
###################################################################"""

4.3、获取系统内存 + 获取进程(实际内存 + 峰值内存)

def memory_usage():
    import psutil

    # (1)获取系统内存信息
    mem_info = psutil.virtual_memory()
    total_memory = mem_info.total / (1024 ** 3)  # 总内存大小(字节 - GB)
    used_memory = mem_info.used / (1024 ** 3)  # 已使用内存(字节 - GB)
    free_memory = mem_info.available / (1024 ** 3)  # 空闲的内存(字节 - GB)
    print(f"系统总内存RAM: {total_memory} GB")
    print(f"系统已占用内存: {used_memory} GB")
    print(f"系统未占用内存: {free_memory} GB")
    print("*" * 50)

    # (2)获取进程的内存信息
    process = psutil.Process()  # 创建一个进程对象
    mem_info = process.memory_info()  # 获取当前进程在RAM中的内存使用量
    memory_usage = mem_info.rss / (1024 ** 3)  # 表示进程在当前时刻的实际内存使用情况(字节 - GB)
    peak_memory = mem_info.peak_wset / (1024 ** 3)  # 表示进程在任意时间点的内存使用的峰值(字节 - GB)
    print(f"当前进程实际占用内存: {memory_usage_mb:.8f} GB")
    print(f"当前进程最大占用内存: {peak_memory_mb:.8f} GB")

    return memory_usage, peak_memory


if __name__ == "__main__":
    memory_usage()  # 创建对象

"""
系统总内存RAM: 63.74748229980469 GB
系统已占用内存: 8.997417449951172 GB
系统未占用内存: 54.750064849853516 GB
**************************************************
当前进程实际占用内存: 0.01511765 GB
当前进程最大占用内存: 0.01512146 GB
"""

4.4、手动释放内存

"""########################################################################
# 函数: gc.collect(): 手动垃圾回收管理
# 功能:
#     若使用gc.collect():	(1)不能保证立即释放内存,但可以加速自动垃圾回收的执行速度。
#                           (2)其本身也会引起额外的开销,不建议频繁触发手动垃圾回收。
#     若不使用gc.collect():	垃圾回收器是自动定期检测并回收内存,但有一定延迟(定期)。
########################################################################
# 【del 对象】:	(1)使用del语句将对象从命名空间中删除,该对象的内存将被立即释放;
# 				(2)但Python的内存池机制导致该部分占用的内存不会立即释放给计算机,而是等待复用。
# 【对象=None】:	(1)将对象设置为None,该对象的引用计数变为零;
# 				(2)但内存不会立即释放,而是等待自动垃圾回收机制进行内存释放。
########################################################################"""
import gc
import numpy as np


def memory_usage():
    """用于获取当前程序的内存占用情况(单位:MB)"""
    import psutil
    process = psutil.Process()  # 创建一个进程对象,用于获取当前程序的内存信息。
    mem_info = process.memory_info()  # 获取当前进程在RAM中的内存使用量
    memory_usage = mem_info.rss / (1024 ** 2)  # 表示进程在当前时刻的实际内存使用情况(字节 - MB)
    peak_memory = mem_info.peak_wset / (1024 ** 2)  # 表示进程在任意时间点的内存使用的峰值(字节 - MB)
    return memory_usage, peak_memory
    # 1 TB = 1024 GB = [1024^2] MB = [1024^3] KB = [1024^4] Bytes = [1024^4 x 8] bits


if __name__ == "__main__":
    # (1)查看系统初始的内存使用情况
    system_memory, peak_memory = memory_usage()
    print(f"系统初始的内存使用情况(MB): {system_memory:.2f}")
    ######################################################
    # (2)创建一个数组
    array = np.random.randint(0, 100, size=(400, 500, 600))
    print(f"总内存使用情况(MB): {memory_usage()[0]:.2f}, {memory_usage()[1]:.2f}")
    ######################################################
    # (3)查看系统进程的内存使用情况
    array[array <= 2800] = 0  # 灰度强度滤波
    print(f"总内存使用情况(MB): {memory_usage()[0]:.2f}, {memory_usage()[1]:.2f}")
    ######################################################
    # (4)查看(手动垃圾回收)系统进程的内存使用情况
    array = None
    gc.collect()  # 手动垃圾回收:加速自动垃圾回收
    print(f"总内存使用情况(MB): {memory_usage()[0]:.2f}, {memory_usage()[1]:.2f}")

    """
    系统初始的内存使用情况(MB): 29.73
    总内存使用情况(MB): 487.60, 487.61
    总内存使用情况(MB): 487.61, 602.06
    总内存使用情况(MB): 29.85, 602.06
    """

到了这里,关于深入浅出:Python内存管理机制详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入浅出Rust内存安全:构建更安全、高效的系统应用

    在过去几年中,Rust编程语言以其独特的安全保障特性和高效的性能,成为了众多开发者和大型科技公司的新宠。尤其是其内存安全特性,成为了广泛讨论和赞扬的焦点。本文旨在深入探讨内存安全的概念、Rust在内存安全方面的独到之处,以及这些特性对系统开发的深远影响

    2024年02月19日
    浏览(47)
  • Spring高手之路14——深入浅出:SPI机制在JDK与Spring Boot中的应用

       SPI ( Service Provider Interface ) 是一种服务发现机制,它允许第三方提供者为核心库或主框架提供实现或扩展。这种设计允许核心库/框架在不修改自身代码的情况下,通过第三方实现来增强功能。 JDK原生的SPI : 定义和发现 : JDK 的 SPI 主要通过在 META-INF/services/ 目录下放置

    2024年02月09日
    浏览(46)
  • MVCC详解,深入浅出简单易懂

    一、什么是MVCC? mvcc,也就是多版本并发控制,是为了在读取数据时不加锁来提高读取效率和并发性的一种手段。 数据库并发有以下几种场景: 读-读:不存在任何问题。 读-写:有线程安全问题,可能出现脏读、幻读、不可重复读。 写-写:有线程安全问题,可能存在更新丢

    2024年02月04日
    浏览(38)
  • 深入浅出之Docker Compose详解

    目录 1.Docker Compose概述 1.1 Docker Compose 定义 1.2 Docker Compose产生背景 1.3 Docker Compose 核心概念 1.4 Docker Compose 使用步骤 1.5 Docker Compose 常用命令   2. Docker Compose 实战 2.1 Docker Compose下载和卸载 2.2 Docker Compose 项目概述 2.3 Docker Compose 编排字段部分详解 2.3.1 version 2.3.2 services 2.3.3 bui

    2024年02月08日
    浏览(43)
  • 深入浅出 Spring:核心概念和基本用法详解

    个人主页:17_Kevin-CSDN博客 收录专栏;《Java》 在 Java 企业级应用开发中,Spring 框架已经成为了事实上的标准。它提供了一种轻量级的解决方案,使得开发者能够更轻松地构建灵活、可扩展的应用程序。在本文中,我们将探讨 Spring 框架的一些核心概念和基本用法,以此更好地

    2024年03月20日
    浏览(55)
  • 深入浅出对话系统——基于预训练语言模型的对话管理

    主要讲解三篇论文,主要思想是把自然语言理解、对话管理和自然语言生成三部分整合到一起。 数据集 CamRest676 MultiWOZ 都是用的自回归语言模型 causal GPT-2、Transformer Decoder 一个概念:delexicalization 通过相应的占位符替换特定的槽值 占位符作为特定的token,不关心具体的取值

    2024年02月16日
    浏览(68)
  • 【C++深入浅出】STL之string用法详解

    目录 一. 前言 二. STL概要 2.1 什么是STL 2.2 STL的六大组件 2.3 STL的缺陷 三. string类概述 3.1 什么是string类 3.2 为什么要使用string类 四. string类的使用 4.1 包含头文件 4.2 构造函数 4.3 赋值运算符重载 4.4 容量操作 4.5 访问/遍历操作 4.6 查找修改操作 4.7 子串操作 ​4.8 非成员函数  

    2024年02月05日
    浏览(48)
  • SpringCloud与Dubbo的区别(全面详解)深入浅出

    初始定位不同:SpringCloud定位为微服务架构下的一站式解决方案;Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用和治理 生态环境不同:SpringCloud依托于Spring平台,具备更加完善的生态体系;而Dubbo一开始只是做RPC远程调用,生态相对匮乏,现在逐渐丰富起来。 调用方

    2024年02月08日
    浏览(45)
  • 【数据结构与算法篇】深入浅出——二叉树(详解)

    ​👻内容专栏:《数据结构与算法专栏》 🐨本文概括: 二叉树是一种常见的数据结构,它在计算机科学中广泛应用。本博客将介绍什么是二叉树、二叉树的顺序与链式结构以及它的基本操作,帮助读者理解和运用这一重要概念。 🐼本文作者: 花 蝶 🐸发布时间:2023.6.5

    2024年02月08日
    浏览(44)
  • 【深入浅出RocketMQ原理及实战】「底层原理挖掘系列」透彻剖析贯穿RocketMQ的消息消费长轮训机制体系的原理分析

    使用系统控制读取操作的DefaultMQPushConsumer可以自动调用传入的处理方法来处理收到的消息。通过设置各种参数和传入处理消息的函数,使用DefaultMQPushConsumer的主要目的是方便配置和处理消息。在收到消息后,系统会自动保存Offset,并且如果加入了新的DefaultMQPushConsumer,系统会

    2024年02月11日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包