【 OpenGauss源码学习 —— 列存储(CStoreMemAlloc)】

列存储(CStoreMemAlloc)

  • 概述
  • CStoreMemAlloc 类
    • CStoreMemAlloc::Palloc 函数
    • CStoreMemAlloc::AllocPointerNode 函数
    • CStoreMemAlloc::FreePointerNode 函数
    • CStoreMemAlloc::Repalloc 函数
    • CStoreMemAlloc::Pfree
    • CStoreMemAlloc::Register 函数
    • CStoreMemAlloc::Unregister 函数
    • CStoreMemAlloc::Reset 函数
    • CStoreMemAlloc::Init 函数
  • 总结

声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。
本文主要参考了 OpenGauss1.1.0 的开源代码和《OpenGauss数据库源码解析》一书以及OpenGauss社区学习文档和一些参考资料

概述

  学习完了 CUCUStorage 类,我们最后来学习一下 CStoreMemAlloc 类。CStoreMemAlloc 类提供了内存管理的功能,而 CUCUStorage 类负责处理列存储中的具体数据单元和物理存储。在实际的列存储系统中,这些类可能会协同工作以有效地管理内存和存储数据。

CStoreMemAlloc 类

  CStoreMemAlloc 类在列存储中扮演了一个内存管理的角色,帮助管理和释放与列存储操作相关的动态内存。这对于确保系统在处理大量数据时能够高效使用内存防止内存泄漏以及正确处理事务回滚等方面非常重要。类的定义如下:(函数路径:src/include/storage/cstore/cstore_mem_alloc.h

// 类定义:CStoreMemAlloc
// 用于管理从malloc中分配的内存指针
// 在事务出现错误时,可以在abortTransaction中重置malloc的内存
// 在事务提交时,可以重置malloc的内存
class CStoreMemAlloc {
public:static void* Palloc(Size size, bool toRegister = true);static void Pfree(void* pointer, bool registered = true);static void* Repalloc(void* pointer, Size size, Size old_size, bool registered = true);static void Register(void* pointer);static void Unregister(const void* pointer);static void Reset();static void Init();private:static void* AllocPointerNode();static void FreePointerNode(PointerNode* pointer);// 保存所有分配的内存指针数组static THR_LOCAL PointerList m_tab[MaxPointersArryLen];// 记录分配的内存指针数量static THR_LOCAL uint64 m_count;// 保存已经分配的PointerNode的缓存static THR_LOCAL uint32 m_ptrNodeCacheCount;static THR_LOCAL PointerNode* m_ptrNodeCache[MaxPtrNodeCacheLen];
};

  下面我们分别来看看CStoreMemAlloc 类成员函数的作用是什么?

CStoreMemAlloc::Palloc 函数

  CStoreMemAlloc 类中的 Palloc 方法。该方法用于从系统中分配内存,并根据需要将内存指针注册到管理中。具体作用和功能如下:

描述:该方法用于从系统中分配内存,支持动态内存的分配操作。
参数:size:需要分配的内存大小。toRegister:表示是否需要将该内存指针在事务管理范围内进行注册。如果为 true,则注册;如果为 false,则不注册。
功能:确保要分配的内存大小大于0。调用内部的 InnerMalloc 方法进行实际的内存分配。如果内存分配失败,抛出内存不足的错误。如果需要在事务管理范围内注册该内存指针,则进行注册。返回分配的内存指针。

  函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 从系统中分配内存* @Param[IN] size: 需要的内存大小* @Param[IN] toRegister: 如果这块内存在线程管理的范围内,则设置为 true;*                        如果这块内存在进程管理的范围内,则设置为 false。* @See also: 无*/
void* CStoreMemAlloc::Palloc(Size size, bool toRegister)
{// 确保分配的内存大小大于0Assert(size > 0);// 调用内部的分配方法分配内存void* ptr = InnerMalloc(size);// 如果分配失败,抛出内存不足的错误if (ptr == NULL) {ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("malloc fails, out of memory: size %lu", size)));}// 如果需要注册(在事务管理范围内),则进行注册if (toRegister) {/* 步骤2:注册指针 */Register(ptr);}// 返回分配的内存指针return ptr;
}

CStoreMemAlloc::AllocPointerNode 函数

  这段代码是 CStoreMemAlloc 类中的 AllocPointerNode 方法。该方法用于分配一个指针节点,具体作用和功能如下:

描述:该方法用于分配一个指针节点,该节点可能被用于管理 CStoreMemAlloc 类中的内存指针。
返回:返回分配得到的指针节点。
功能:如果指针节点缓存中有可用节点,从缓存中取出一个节点。如果指针节点缓存中没有可用节点,直接使用 malloc 分配一个新的节点。如果分配失败,抛出内存不足的错误。返回分配得到的指针节点。

  函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 分配一个指针节点* @Return: 分配得到的指针节点* @See also: 无*/
void* CStoreMemAlloc::AllocPointerNode()
{PointerNode* ptr = NULL;// 如果缓存中有可用节点,从缓存中取出if (m_ptrNodeCacheCount > 0) {ptr = m_ptrNodeCache[--m_ptrNodeCacheCount];} else {// 如果缓存中没有可用节点,直接使用malloc分配新节点ptr = (PointerNode*)malloc(sizeof(PointerNode));// 分配失败则抛出内存不足的错误if (ptr == NULL) {ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("malloc fails, out of memory")));}}// 返回分配得到的指针节点return ptr;
}

CStoreMemAlloc::FreePointerNode 函数

  CStoreMemAlloc 类中的 FreePointerNode 方法用于释放一个指针节点,具体作用和功能如下:

描述:该方法用于释放一个指针节点,该节点可能被用于管理 CStoreMemAlloc 类中的内存指针。
参数:ptr 为要释放的指针节点。
功能:如果指针节点缓存未满,将节点放入缓存中以便后续复用。如果指针节点缓存已满,直接使用 free 释放节点。

  函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 释放一个指针节点* @Param[IN] ptr: 要释放的指针节点* @See also: 无*/
void CStoreMemAlloc::FreePointerNode(PointerNode* ptr)
{// 如果指针节点缓存未满,将节点放入缓存中if (m_ptrNodeCacheCount < MaxPtrNodeCacheLen) {m_ptrNodeCache[m_ptrNodeCacheCount++] = ptr;} else {// 如果缓存已满,直接使用free释放节点free(ptr);}
}

CStoreMemAlloc::Repalloc 函数

  CStoreMemAlloc 类中的 Repalloc 方法用于重新分配内存(相当于 remalloc 操作),并根据需要注册新分配的内存取消注册旧内存。具体作用和功能如下:

描述:该方法用于重新分配内存,类似于系统中的 remalloc 操作,同时支持内存的注册和取消注册。
参数:old_size:旧内存的大小。size:新内存的大小。pointer:要释放的旧内存指针。registered:如果在调用 Palloc() 时传递 true,则为 true;如果传递 false,则为 false。
功能:断言,确保内存指针和大小的合法性。调用内部的 InnerMalloc 方法重新分配内存。如果分配失败,抛出内存不足的错误。将旧内存中的数据拷贝到新分配的内存中。如果在 Palloc() 中传递 true,则注册新分配的内存,取消注册旧内存。断言,确保计数器大于0。释放旧内存。返回新分配的内存指针。

  函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 重新分配内存(remalloc)从系统中* @Param[IN] old_size: 旧内存大小* @Param[IN] size:     新内存大小* @Param[IN] pointer:  要释放的内存指针* @Param[IN] registered: 如果在 Palloc() 中传递 true,则为 true;*                        如果在 Palloc() 中传递 false,则为 false。* @See also: 无*/
void* CStoreMemAlloc::Repalloc(void* pointer, Size size, Size old_size, bool registered)
{// 断言,确保内存指针和大小的合法性Assert(pointer != NULL);Assert(size > 0);// 调用内部的 InnerMalloc 方法重新分配内存void* ptr = InnerMalloc(size);// 如果分配失败,抛出内存不足的错误if (ptr == NULL) {ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory")));}// 将旧内存中的数据拷贝到新分配的内存中errno_t rc = memcpy_s(ptr, size, pointer, old_size);securec_check_c(rc, "\0", "\0");// 如果在 Palloc() 中传递 true,则注册新分配的内存,取消注册旧内存if (registered) {Register(ptr);Unregister(pointer);// 断言,确保计数器大于0Assert(m_count > 0);}// 释放旧内存free(pointer);// 返回新分配的内存指针return ptr;
}

CStoreMemAlloc::Pfree

  CStoreMemAlloc 类中的 Pfree 方法用于将内存释放到系统,同时根据需要取消注册内存指针。具体作用和功能如下:

描述:该方法用于释放内存到系统,可以选择是否取消注册内存指针。
参数:pointer:要释放的内存指针。registered:如果在调用 Palloc() 时传递 true,则为 true;如果传递 false,则为 false。
功能:断言,确保内存指针的合法性。如果在 Palloc() 中传递 true,则取消注册内存指针。释放内存到系统。

  函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 释放内存到系统* @Param[IN] pointer: 要释放的内存指针* @Param[IN] registered: 如果在 Palloc() 中传递 true,则为 true;*                        如果在 Palloc() 中传递 false,则为 false。* @See also: 无*/
void CStoreMemAlloc::Pfree(void* pointer, bool registered)
{// 断言,确保内存指针的合法性Assert(pointer);// 如果在 Palloc() 中传递 true,则取消注册内存指针if (registered) {Unregister(pointer);}// 释放内存到系统free(pointer);
}

CStoreMemAlloc::Register 函数

  CStoreMemAlloc 类中的 Register 方法用于注册内存指针,将其添加到内存指针管理表中。具体作用和功能如下:

描述:该方法用于将内存指针注册,将其添加到内存指针管理表中,以便在事务结束时进行统一的处理。
参数:pointer:要注册的内存指针。
功能:断言,确保 MaxPointersArryLen 是2的幂。计算内存指针在管理表中的索引位置。如果链表为空,头尾节点都指向新分配的节点。如果链表不为空,在链表尾部添加新节点。增加内存指针计数器。

  函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 注册内存指针* @Param[IN] pointer: 要注册的内存指针* @See also: AllocPointerNode()*/
void CStoreMemAlloc::Register(void* pointer)
{// 断言,确保 MaxPointersArryLen 是2的幂Assert((MaxPointersArryLen & (MaxPointersArryLen - 1)) == 0);// 计算索引位置int idx = PointerGetDatum(pointer) & (MaxPointersArryLen - 1);PointerNode* nodePtr = m_tab[idx].tail;// 如果尾节点为空,说明链表为空if (nodePtr == NULL) {// 头尾节点都指向新分配的节点Assert(m_tab[idx].header == NULL);m_tab[idx].header = m_tab[idx].tail = (PointerNode*)AllocPointerNode();m_tab[idx].header->ptr = pointer;m_tab[idx].header->next = NULL;} else {// 否则在链表尾部添加新节点nodePtr->next = (PointerNode*)AllocPointerNode();nodePtr->next->ptr = pointer;nodePtr->next->next = NULL;m_tab[idx].tail = nodePtr->next;}// 增加计数器++m_count;
}

CStoreMemAlloc::Unregister 函数

  CStoreMemAlloc 类中的 Unregister 方法用于取消注册内存指针,将其从内存指针管理表中移除。具体作用和功能如下:

描述:该方法用于取消注册内存指针,将其从内存指针管理表中移除,以便在事务结束时进行统一的处理。
参数:pointer:要取消注册的内存指针。
功能:断言,确保内存指针和计数器的合法性。确定包含该指针的节点列表。在节点列表中查找指针,如果找到则移除该节点。如果取消注册的是尾节点,需要修改尾指针。重置并释放节点。减少计数器。断言,确保找到了要取消注册的指针节点。

  函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 取消注册内存指针* @Param[IN] pointer: 要取消注册的内存指针* @See also: FreePointerNode()*/
void CStoreMemAlloc::Unregister(const void* pointer)
{// 断言,确保内存指针和计数器的合法性Assert(pointer && m_count > 0);// Step 1: 确定包含该指针的节点列表Assert((MaxPointersArryLen & (MaxPointersArryLen - 1)) == 0);int idx = PointerGetDatum(pointer) & (MaxPointersArryLen - 1);// Step 2: 在节点列表中查找指针PointerNode* nodePtr = m_tab[idx].header;Assert(nodePtr);PointerNode* prePtr = NULL;while (nodePtr != NULL) {if (nodePtr->ptr == pointer) {// 如果前一个节点为空,说明要取消注册的是头节点if (prePtr == NULL) {m_tab[idx].header = nodePtr->next;// 如果这个列表只有一个节点if (m_tab[idx].tail == nodePtr) {Assert(m_tab[idx].header == NULL);m_tab[idx].tail = NULL;}} else {// 否则,修改前一个节点的 next 指针prePtr->next = nodePtr->next;// 如果取消注册的是尾节点,需要修改尾指针if (m_tab[idx].tail == nodePtr) {m_tab[idx].tail = prePtr;Assert(m_tab[idx].tail->next == NULL);}}// 重置并释放节点nodePtr->Reset();FreePointerNode(nodePtr);break;}prePtr = nodePtr;nodePtr = nodePtr->next;}// 减少计数器--m_count;// 断言,确保找到了要取消注册的指针节点Assert(nodePtr != NULL);
}

CStoreMemAlloc::Reset 函数

  CStoreMemAlloc 类中的 Reset 方法用于重置内存指针管理器的状态释放所有注册的内存。具体作用和功能如下:

描述:该方法用于在事务结束时,重置内存指针管理器的状态,释放所有注册的内存。
功能:如果存在注册的内存指针:Step 1: 释放 m_tab 中的每个列表中的内存指针。遍历 m_tab 数组,释放每个列表中的内存指针。注意,必须将列表的头尾节点重置为 NULL,因为线程可能被重用。断言,确保释放的内存数和计数器一致。Step 2: 释放缓存的节点(如果有的话)。释放缓存的节点,以便在下一次使用时重新分配。

  这个方法的目的是确保在事务结束时,所有注册的内存都被正确释放,以避免内存泄漏。函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 重置内存指针管理器状态,释放所有注册的内存*/
void CStoreMemAlloc::Reset()
{uint32 i = 0;uint32 freeNum = 0;// 如果存在注册的内存指针if (m_count) {// Step 1: 释放 m_tab 中的每个列表for (i = 0; i < MaxPointersArryLen; ++i) {PointerNode* nodePtr = m_tab[i].header;PointerNode* tmpPtr = NULL;// 释放每个列表中的内存指针while ((nodePtr != NULL) && (nodePtr->ptr != NULL)) {free(nodePtr->ptr);tmpPtr = nodePtr->next;free(nodePtr);nodePtr = tmpPtr;++freeNum;}// 注意,必须将 header 和 tail 重置为 NULL// 因为线程可能被重用m_tab[i].header = NULL;m_tab[i].tail = NULL;}// 断言,确保释放的内存数和计数器一致Assert(m_count == freeNum);m_count = 0;}// Step 2: 释放缓存的节点(如果有的话)for (i = 0; i < m_ptrNodeCacheCount; ++i) {free(m_ptrNodeCache[i]);}m_ptrNodeCacheCount = 0;
}

CStoreMemAlloc::Init 函数

  这段代码是 CStoreMemAlloc 类中的 Init 方法。该方法用于初始化内存指针管理器的状态。具体作用和功能如下:

描述:该方法用于在开始新的事务时,初始化内存指针管理器的状态。
功能:重置计数器。断言,确保 MaxPointersArryLen 是2的幂。初始化 m_tab 数组,将每个列表的头尾节点都设置为 NULL。初始化缓存节点计数器。

  这个方法的目的是确保在每次开始新的事务时,内存指针管理器都处于初始状态。函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_mem_alloc.cpp

/** @Description: 初始化内存指针管理器*/
void CStoreMemAlloc::Init()
{// 重置计数器m_count = 0;// 断言,确保 MaxPointersArryLen 是2的幂Assert((MaxPointersArryLen & (MaxPointersArryLen - 1)) == 0);// 初始化 m_tab 数组for (uint32 i = 0; i < MaxPointersArryLen; ++i) {m_tab[i].header = NULL;m_tab[i].tail = NULL;}// 初始化缓存节点计数器m_ptrNodeCacheCount = 0;
}

总结

CStoreMemAlloc
作用: CStoreMemAlloc 类用于管理列存储中的内存分配和释放
功能:

  • Palloc 方法: 分配内存,并根据需要注册到管理器。
  • FreePointerNode 方法: 释放缓存的节点。
  • Repalloc 方法: 重新分配内存,同时处理注册和取消注册。
  • Pfree 方法: 释放内存,同时处理取消注册。
  • Register 方法: 注册内存指针,将其添加到管理表。
  • Unregister 方法: 取消注册内存指针,将其从管理表中移除。
  • Reset 方法: 重置管理器状态,释放所有注册的内存。
  • Init 方法: 初始化管理器状态。

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

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

相关文章

杭电oj 2064 汉诺塔III C语言

#include <stdio.h>void main() {int n, i;long long sum[35] { 2,8,26 };for (i 3; i < 35; i)sum[i] 3 * sum[i - 1] 2;while (~scanf_s("%d", &n))printf("%lld\n", sum[n - 1]); }

问鼎web服务

华子目录 www简介常见Web服务程序介绍&#xff1a;服务器主机主要数据浏览器网址及http介绍urlhttp请求方法 http协议请求的工作流程www服务器类型静态网站动态网站 快速安装Apache安装准备工作httpd所需目录主配置文件 实验操作 www简介 Web网络服务也叫www&#xff08;world…

编码的发展历史

编码的发展历史 ASCII&#xff1a; ASCII编码使用7位二进制数表示一个字符&#xff0c;范围从0到127。每个字符都有一个唯一的ASCII码值与之对应。例如&#xff0c;大写字母"A"的ASCII码是65&#xff0c;小写字母"a"的ASCII码是97。 ASCII字符集包括英文…

linux服务器安装gitlab

一、安装gitlab sudo yum install curl policycoreutils-python openssh-server openssh-clients sudo systemctl enable sshd sudo systemctl start sshd sudo firewall-cmd --permanent --add-servicehttp curl https://packages.gitlab.com/install/repositories/gitla…

LabVIEW中将SMU信号连接到PXI背板触发线

LabVIEW中将SMU信号连接到PXI背板触发线 本文介绍如何将信号从PXI&#xff08;e&#xff09;SMU卡路由到PXI&#xff08;e&#xff09;机箱上的背板触发线。该过程涉及使用NI-DCPowerVI将SMU信号导出到PXI_TRIG线上。 在继续操作之前&#xff0c;请确保在开发PC上安装了兼容版…

MySQL启动MySQL8.0并指定配置文件

MySQL启动MySQL8.0并指定配置文件 mkdir -p /mysql8hello/config ; mkdir -p /mysql8hello/data ; mkdir -p /mysql8hello/logs; mkdir -p /mysql8hello/conf; vim /mysql8hello/config/my.cnf; # 启动报错就修改成777&#xff0c;但是会提示风险 chmod 644 /mysql8hello/co…

d3dx9_43.dll缺失怎么办?教你一分钟修复d3dx9_43.dll丢失问题

今天&#xff0c;与大家分享关于“d3dx9_43.dll丢失的5个解决方法”的主题。在我们的日常生活和工作中&#xff0c;我们可能会遇到各种各样的问题&#xff0c;而d3dx9_43.dll丢失就是其中之一。那么&#xff0c;什么是d3dx9_43.dll呢&#xff1f;它为什么会丢失&#xff1f;又该…

【LeetCode刷题-链表】--25.K个一组翻转链表

25.K个一组翻转链表 思路&#xff1a; 把链表节点按照k个一组分组&#xff0c;可以使用一个指针head依次指向每组的头节点&#xff0c;这个指针每次向前移动k步&#xff0c;直至链表结尾&#xff0c;对于每个分组&#xff0c; 先判断它的长度是否大于等于k&#xff0c;若是&am…

什么是Zero-shot(零次学习)

1 Zero-shot介绍 Zero-shot学习&#xff08;ZSL&#xff09;是机器学习领域的一种先进方法&#xff0c;它旨在使模型能够识别、分类或理解在训练过程中未见过的类别或概念。这种学习方法对于解决现实世界中常见的长尾分布问题至关重要&#xff0c;即对于一些罕见或未知类别的样…

商务俄语学习,柯桥基础入门教学,千万别小看俄语中的“что”

1、что до (чего) 至于 例&#xff1a; что до меня, то я не могу согласиться 至于我&#xff0c;我不能同意。 А что до зимовки... Ты приедешь в этом году? 说到冬天和过冬…你今年回来吗…

在windows笔记本中安装tensorflow1.13.2版本的gpu环境2

tensorflow1.13.2版本的gpu环境 看python-anacona的安装只需要看1.1部分即可 目录 1.1 Anaconda安装 1.2 tensorflow-gpu安装 1.3 python编译器-pycharm安装 1.1 Anaconda安装 从镜像源处下载anaconda&#xff0c;地址&#xff1a;Index of /anaconda/archive/ | 北京…

PTA-6-45 工厂设计模式-运输工具

题目如下&#xff1a; 工厂类用于根据客户提交的需求生产产品&#xff08;火车、汽车或拖拉机&#xff09;。火车类有两个子类属性&#xff1a;车次和节数。拖拉机类有1个子类方法耕地&#xff0c;方法只需简单输出“拖拉机在耕地”。为了简化程序设计&#xff0c;所有…

基于docker实现JMeter分布式压测

为什么需要分布式&#xff1f; 在工作中经常需要对一些关键接口做高QPS的压测&#xff0c;JMeter是由Java 语言开发&#xff0c;没创建一个线程&#xff08;虚拟用户&#xff09;&#xff0c;JVM默认会为每个线程分配1M的堆栈内存空间。受限于单台试压机的配置很难实现太高的并…

LeetCode59.螺旋矩阵

LeetCode59.螺旋矩阵 1.问题描述2.解题思路3.代码 1.问题描述 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,…

Codeforces Round 822 (Div. 2)(D前缀和+贪心加血量)

A.选三条相邻的边遍历一次求最小值 #include<bits/stdc.h> using namespace std; const int N 1e610,mod1e97; #define int long long int n,m; vector<int> g[N]; int a[N]; void solve() {cin>>n;int res2e18;for(int i1;i<n;i) cin>>a[i];sort…

谈一谈什么是接口测试?怎样做接口测试?

扫盲内容&#xff1a; 1.什么是接口&#xff1f; 2.接口都有哪些类型&#xff1f; 3.接口的本质是什么&#xff1f; 4.什么是接口测试&#xff1f; 5.问什么要做接口测试&#xff1f; 6.怎样做接口测试&#xff1f; 7.接口测测试点是什么&#xff1f; 8.接口测试都要掌…

童装店铺如何通过软文增加客流量

在信息超负载、媒介粉尘化、产品同质化多重因素下&#xff0c;传统营销疲态尽显、日渐式微&#xff0c;很难支撑新环境下品牌和企业的持续增长。聚焦童装行业更是如此&#xff0c;一方面用户迭代速度快&#xff0c;另一方面&#xff0c;新时代父母的育儿观念更加精细化&#xf…

安装pytorch

cuda≤11.6&#xff0c;观察控制面板 观察torch对应cuda版本 https://download.pytorch.org/whl/torch/ 安装cuda11.6.0 CUDA Toolkit Archive | NVIDIA Developer cmd输入nvcc -V 编辑国内镜像源 .condarc anaconda prompt输入 查看环境 conda env list 安装py3.9…

MySQL面试,MySQL事务,MySQL锁,MySQL集群,主从,MySQL分区,分表,InnoDB

文章目录 数据库-MySQLMySQL主从、集群模式简单介绍1、主从模式 Replication2、集群模式3、主从模式部署注意事项 UNION 和 UNION ALL 区别分库分表1.垂直拆分2、水平拆分 MySQL有哪些数据类型1、整数类型**&#xff0c;2、实数类型**&#xff0c;3、字符串类型**&#xff0c;4…

DDoS攻击频发,科普防御DDoS攻击的几大有效方法

谈到目前最凶猛、频率高&#xff0c;且令人深恶痛绝的网络攻击&#xff0c;DDoS攻击无疑能在榜上占有一席之地。各种规模的企业报包括组织机构都可能受到影响&#xff0c;它能使企业宕机数小时以上&#xff0c;给整个互联网造成无数损失。可以说&#xff0c;怎样防御DDoS攻击是…