Linux 6.6内核内存管理深度解析(十五):CMA 连续内存分配器

引言:GPU 要一块"物理连续"的缓冲区,buddy 却凑不出来

想象一块 GPU:它的 DMA 引擎要一块 4MB 的物理连续 内存当帧缓冲(framebuffer)。设备 DMA 不像 CPU------它没有 MMU 页表,只能对着连续的物理地址搬数据。

问题来了:buddy 分配器(#2)按 2 的幂给页,系统跑久了,4KB 空闲页东一块西一块,alloc_pages(order=10)(4MB)大概率失败------不是没内存,是凑不出连续块(外部碎片,正是 #9 讲的问题)。

compaction(#9)能"事后规整"凑连续块,但它是被动 + 有延迟 的------等设备要分配了才去规整,可能来不及。CMA(Contiguous Memory Allocator,连续内存分配器) 换个思路:启动时就预留一大块连续物理内存区,平时让 movable 页"借住",设备真要用时把这些 movable 页迁走、瞬间腾出连续区。

这篇讲的就是这条链路:预留(MIGRATE_CMA)→ 借用(buddy 把 movable 页分进去)→ 腾出(alloc_contig_range 迁走 movable 页)→ 分配(dma_alloc_contiguous)。


全景图

#mermaid-svg-WVtqGC5goZZaoEZO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WVtqGC5goZZaoEZO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WVtqGC5goZZaoEZO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WVtqGC5goZZaoEZO .error-icon{fill:#552222;}#mermaid-svg-WVtqGC5goZZaoEZO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WVtqGC5goZZaoEZO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WVtqGC5goZZaoEZO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WVtqGC5goZZaoEZO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WVtqGC5goZZaoEZO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WVtqGC5goZZaoEZO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WVtqGC5goZZaoEZO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WVtqGC5goZZaoEZO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WVtqGC5goZZaoEZO .marker.cross{stroke:#333333;}#mermaid-svg-WVtqGC5goZZaoEZO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WVtqGC5goZZaoEZO p{margin:0;}#mermaid-svg-WVtqGC5goZZaoEZO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WVtqGC5goZZaoEZO .cluster-label text{fill:#333;}#mermaid-svg-WVtqGC5goZZaoEZO .cluster-label span{color:#333;}#mermaid-svg-WVtqGC5goZZaoEZO .cluster-label span p{background-color:transparent;}#mermaid-svg-WVtqGC5goZZaoEZO .label text,#mermaid-svg-WVtqGC5goZZaoEZO span{fill:#333;color:#333;}#mermaid-svg-WVtqGC5goZZaoEZO .node rect,#mermaid-svg-WVtqGC5goZZaoEZO .node circle,#mermaid-svg-WVtqGC5goZZaoEZO .node ellipse,#mermaid-svg-WVtqGC5goZZaoEZO .node polygon,#mermaid-svg-WVtqGC5goZZaoEZO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WVtqGC5goZZaoEZO .rough-node .label text,#mermaid-svg-WVtqGC5goZZaoEZO .node .label text,#mermaid-svg-WVtqGC5goZZaoEZO .image-shape .label,#mermaid-svg-WVtqGC5goZZaoEZO .icon-shape .label{text-anchor:middle;}#mermaid-svg-WVtqGC5goZZaoEZO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WVtqGC5goZZaoEZO .rough-node .label,#mermaid-svg-WVtqGC5goZZaoEZO .node .label,#mermaid-svg-WVtqGC5goZZaoEZO .image-shape .label,#mermaid-svg-WVtqGC5goZZaoEZO .icon-shape .label{text-align:center;}#mermaid-svg-WVtqGC5goZZaoEZO .node.clickable{cursor:pointer;}#mermaid-svg-WVtqGC5goZZaoEZO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WVtqGC5goZZaoEZO .arrowheadPath{fill:#333333;}#mermaid-svg-WVtqGC5goZZaoEZO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WVtqGC5goZZaoEZO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WVtqGC5goZZaoEZO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WVtqGC5goZZaoEZO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WVtqGC5goZZaoEZO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WVtqGC5goZZaoEZO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WVtqGC5goZZaoEZO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WVtqGC5goZZaoEZO .cluster text{fill:#333;}#mermaid-svg-WVtqGC5goZZaoEZO .cluster span{color:#333;}#mermaid-svg-WVtqGC5goZZaoEZO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WVtqGC5goZZaoEZO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WVtqGC5goZZaoEZO rect.text{fill:none;stroke-width:0;}#mermaid-svg-WVtqGC5goZZaoEZO .icon-shape,#mermaid-svg-WVtqGC5goZZaoEZO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WVtqGC5goZZaoEZO .icon-shape p,#mermaid-svg-WVtqGC5goZZaoEZO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WVtqGC5goZZaoEZO .icon-shape .label rect,#mermaid-svg-WVtqGC5goZZaoEZO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WVtqGC5goZZaoEZO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WVtqGC5goZZaoEZO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WVtqGC5goZZaoEZO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 启动预留

cma_declare_contiguous_nid :239
标记 MIGRATE_CMA 区

mmzone.h:62
平时: movable 页借用

buddy 把 movable 页分进 CMA 区
设备要连续内存

dma_alloc_contiguous :357
cma_alloc cma.c:429

bitmap 找空闲位
alloc_contig_range :6109

腾出连续区
start_isolate_page_range :6149

隔离 pageblock
__alloc_contig_migrate_range :6030

迁走 movable 页(复用 #9)
isolate_freepages_range :6217

摘出空闲连续页
设备拿到连续物理内存

DMA 直接搬数据

一句话:启动预留 MIGRATE_CMA 区(movable 页平时借用)→ 设备 dma_alloc_contiguous 时 cma_alloc 用 bitmap 找空闲位 → alloc_contig_range 隔离 pageblock、迁走 movable 页、摘出连续空闲页 → 设备拿到物理连续内存做 DMA。


一、CMA 是什么:预留 + 借用 + 腾出

1.1 为什么 buddy 给不了连续块

buddy(#2)按 2 的幂分配,空闲页会随着分配/释放被切碎成小 order 的块。系统长期运行后,虽然空闲总量够,但凑不出高阶连续块(外部碎片,#9 详述)。而设备 DMA 恰恰要物理连续------这是"按需分配"的 buddy 与"要连续"的设备之间的根本矛盾。

1.2 CMA 的三步设计

CMA 的核心思想是把"连续"这个属性提前锁定,而不是等用时再凑:

阶段 干什么 关键点
预留 启动时划出一大块连续物理内存,标记 MIGRATE_CMA 连续性是"生下来就有"的
借用 平时这块内存闲着浪费,让 movable 页(可迁移的用户页)借住 不独占,内存不浪费
腾出 设备要用时,把借住的 movable 页迁走,瞬间腾出连续区 复用 #9 compaction 的迁移

关键在"借用":CMA 区不是 从 buddy 里完全隔离的死区,而是允许 movable 页住进来 ------这样设备不用时,CMA 区照样能被普通分配利用,内存不浪费。设备要用时,alloc_contig_range 把这些 movable 页迁到别处(它们本来就能搬),腾出连续块。

Why 只借给 movable、不借给 unmovable :CMA 腾出连续区靠的是"迁移"(把页搬走)。而 MIGRATE_UNMOVABLE(内核直接映射、DMA pin 的页)物理地址是约定死的,搬不动 (#9 讲过)。所以 CMA 区只允许 movable 页借住------设备要用了,随时能把它们迁走;若让 unmovable 页住进来,设备来了就卡死。这也是为什么 MIGRATE_CMA 和 MIGRATE_MOVABLE 关系紧密(is_migrate_movable 把 movable 和 CMA 一起当作"可迁移",mmzone.h:81)。


二、预留:cma_declare_contiguous 标记 MIGRATE_CMA 区

2.1 预留接口

启动时(或设备驱动 probe 时)调 cma_declare_contiguous_nid(cma.c:239)预留一块 CMA 区:

c 复制代码
// cma_declare_contiguous_nid(mm/cma.c:239)
int __init cma_declare_contiguous_nid(phys_addr_t base,
			phys_addr_t size, phys_addr_t limit,
			phys_addr_t alignment, unsigned int order_per_bit,
			bool fixed, const char *name, struct cma **res_cma,
			int nid)

参数里关键的是 size(预留多大)和 order_per_bit(bitmap 一个 bit 代表多少页,通常 pageblock_order)。它把这块内存从 memblock 里"圈"出来(固定 base 或从 limit 以内挑),建立 struct cma 描述符。

2.2 struct cma:一块 CMA 区的描述符

c 复制代码
// struct cma(mm/cma.h:13)
struct cma {
	unsigned long base_pfn;      // CMA 区起始页帧
	unsigned long count;         // 总页数
	unsigned long *bitmap;       // 位图:哪段被分配了
	unsigned int order_per_bit;  // 一个 bit 代表多少页(通常 pageblock)
	...
};

bitmap 是 CMA 分配的核心:一个 bit 代表 order_per_bit 个页的一段 。分配时找一段连续的空闲 bit(bitmap_find_next_zero_area_off),置位表示"这段被占了"。这样"找连续空间"就变成"找位图里连续的 0",O(n) 高效。

2.3 MIGRATE_CMA:一种特殊的 migratetype

预留的 CMA 区的 pageblock 被标记为 MIGRATE_CMA(mmzone.h:62,enum migratetype 里的一种)。源码注释(:53-61)点破了它的设计意图:

MIGRATE_CMA migration type is designed to mimic the way ZONE_MOVABLE works... movable pages are migrated away from MIGRATE_CMA pageblocks and page allocator never implicitly change migration type of MIGRATE_CMA pageblock.

两个要点:

  1. buddy 可以把 movable 页分进 CMA 区 ------这就是"借用"。注意机制:CMA 不在 fallbacks[] 数组(page_alloc.c:1597,只有 UNMOVABLE/RECLAIMABLE/MOVABLE 三者互 fallback)里,而是走独立的 __rmqueue_cma_fallback(:1604)路径 ------分配类型是 MIGRATE_MOVABLE 时,gfp_to_alloc_flags_cma(:3033)置 ALLOC_CMA 标志,__rmqueue(:2086)才从 CMA 区拿页,还带一条平衡策略:CMA 空闲页超过 zone 空闲一半就优先从 CMA 拿(:2092-2096,避免 regular 区被挤爆)。
  2. CMA 区不会被 buddy 隐式改成别的类型 ------它永远是 MIGRATE_CMA,随时能被识别并腾出。

三、分配:dma_alloc_contiguous → cma_alloc

设备驱动要连续内存,走 dma_alloc_contiguous(kernel/dma/contiguous.c:357)。它按优先级挑 CMA 区------设备专属区 dev->cma_area → NUMA per-node 区 → 默认全局区,中间还挡一道"单页本来就连续,别浪费 CMA":

c 复制代码
// dma_alloc_contiguous(kernel/dma/contiguous.c:357)------ 关键片段
struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
{
	if (!gfpflags_allow_blocking(gfp))      // ① CMA 要迁页=要能睡,不能睡直接放弃
		return NULL;
	if (dev->cma_area)                       // ② 设备专属 CMA 区
		return cma_alloc_aligned(dev->cma_area, size, gfp);
	if (size <= PAGE_SIZE)                   // ③ 单页物理必然连续,别浪费 CMA
		return NULL;
	...                                      // ④ NUMA per-node 区(CONFIG_DMA_NUMA_CMA)
	return cma_alloc_aligned(dma_contiguous_default_area, size, gfp);  // ⑤ 默认全局区
}

// cma_alloc_aligned(contiguous.c:335)------ 把 size 换算成页数 + align,再进 cma_alloc
align = min(get_order(size), CONFIG_CMA_ALIGNMENT);
return cma_alloc(cma, size >> PAGE_SHIFT, align, gfp & __GFP_NOWARN);

cma_alloc_aligned 只是薄薄一层换算,真正的分配在 cma_alloc(cma.c:429):

c 复制代码
// cma_alloc(mm/cma.c:429)------ 关键片段
for (;;) {
	spin_lock_irq(&cma->lock);
	bitmap_no = bitmap_find_next_zero_area_off(cma->bitmap,
			bitmap_maxno, start, bitmap_count, mask, offset);  // ① 找连续空闲位
	if (bitmap_no >= bitmap_maxno) { ... break; }
	bitmap_set(cma->bitmap, bitmap_no, bitmap_count);            // ② 标记这段被占
	spin_unlock_irq(&cma->lock);

	pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit);
	mutex_lock(&cma_mutex);
	ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA,     // ③ 真正腾出连续区
				 GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0));
	mutex_unlock(&cma_mutex);
	if (ret == 0) {
		page = pfn_to_page(pfn);
		break;
	}
	cma_clear_bitmap(cma, pfn, count);                           // 失败回滚 bitmap
	if (ret != -EBUSY)
		break;
	/* try again with a bit different memory target */
	start = bitmap_no + mask + 1;                                // ④ -EBUSY 换位置重试
}

三步:bitmap 找连续空闲位 → 标记 → alloc_contig_range 真正腾出连续物理页 。alloc_contig_range 返回 -EBUSY 说明这块的 movable 页迁不走(比如有页正被 pin),就回滚 bitmap、换个位置重试。


四、腾出连续区:alloc_contig_range

alloc_contig_range(page_alloc.c:6109)是 CMA 的心脏------它把"被 movable 页借住"的连续区腾空。四步:

c 复制代码
// alloc_contig_range(page_alloc.c:6109)------ 关键片段
struct compact_control cc = {
	.order = -1,
	.mode = MIGRATE_SYNC,
	.alloc_contig = true,            // 标记: 这是"腾连续区"而非"消碎片"
	...
};

ret = start_isolate_page_range(start, end, migratetype, 0, gfp_mask);  // ① 隔离
...
drain_all_pages(cc.zone);                                                // ② 清 per-cpu 缓存

ret = __alloc_contig_migrate_range(&cc, start, end);                     // ③ 迁走 movable 页
...
outer_end = isolate_freepages_range(&cc, outer_start, end);              // ④ 摘出连续空闲页

四步拆开:

  1. start_isolate_page_range(:6149) :把范围内的 pageblock 标记 MIGRATE_ISOLATE------临时"冻结"这一整段,阻止 buddy 再往里面分配,也防止别人并发动它。
  2. drain_all_pages(:6153):把各 CPU 的 per-cpu 页缓存清空,让散落的空闲页回到 buddy,方便后续统一处理。
  3. __alloc_contig_migrate_range(:6165) :把隔离区里还占着的 movable 页迁走------这是复用 #9 compaction 的核心。
  4. isolate_freepages_range(:6217):把腾出来的连续空闲页从 buddy 摘出来,交给调用者(设备)。

4.1 迁移复用 compaction 引擎

第 ③ 步 __alloc_contig_migrate_range(page_alloc.c:6030)的第一行注释说得直白:

c 复制代码
/* This function is based on compact_zone() from compaction.c. */
int __alloc_contig_migrate_range(struct compact_control *cc,
					unsigned long start, unsigned long end)
{
	...
	while (pfn < end || !list_empty(&cc->migratepages)) {
		if (list_empty(&cc->migratepages)) {
			ret = isolate_migratepages_range(cc, pfn, end);   // ① 隔离 movable 页
			...
		}
		...
		ret = migrate_pages(&cc->migratepages, alloc_migration_target,
			NULL, (unsigned long)&mtc, cc->mode, MR_CONTIG_RANGE, NULL);  // ② 迁走
		...
	}
}

它逐段 把 movable 页隔离(isolate_migratepages_range)→ 迁走(migrate_pages,migrate.c:1885)。MR_CONTIG_RANGE 标记"这次迁移是为腾连续区"。

Why CMA 复用 compaction 而不是重写一套 :#9 的 compaction 已经解决"把 movable 页从 A 搬到 B、腾出连续空间"这件事,compact_control + isolate_migratepages + migrate_pages 这套引擎是现成的。CMA 只是换了目标 ------compaction 是"整个 zone 扫描、把碎片挤到一起",CMA 是"就这一块 [start, end) 范围、把里面的 movable 页全搬出去"。所以 alloc_contig_range 构造一个 compact_control(alloc_contig = true、mode = MIGRATE_SYNC)复用同一套迁移代码。这正是内核"同一引擎、不同调用方"的复用典范------compaction、NUMA 迁移(#14)、CMA 三者的 migrate_pages 调用方。


五、释放:cma_release

设备用完连续内存,dma_free_contiguous(contiguous.c:407)→ cma_release(cma.c:560):

c 复制代码
// cma_release(mm/cma.c:560)------ 关键片段
bool cma_release(struct cma *cma, const struct page *pages,
		 unsigned long count)
{
	if (!cma_pages_valid(cma, pages, count))
		return false;

	...
	free_contig_range(pfn, count);   // ① 把连续页还给 buddy
	cma_clear_bitmap(cma, pfn, count);  // ② 清 bitmap 对应位
	...
}

释放就是把连续页还给 buddy(free_contig_range)、清 bitmap 位。还回去的页又被标回 MIGRATE_CMA,于是又能被 movable 页借用------CMA 区回到"闲着等下一次设备分配"的循环。


六、与前面各篇的关系

篇 关系
#2 buddy CMA 区是 buddy 里一块特殊 MIGRATE_CMA 区,buddy 平时把 movable 页分进去
#9 compaction alloc_contig_range 复用 compact_control + isolate_migratepages + migrate_pages,只是范围限定在 [start, end)
#6 GUP GUP pin 的页不可迁移,会挡住 CMA 腾出(-EBUSY)------pin 页和 CMA 连续内存天然冲突
#14 NUMA cma_declare_contiguous_nid 可指定 node,CMA 区有 NUMA 亲和

七、与 GPU / AI Infra 的关系 + 记住三点

7.1 CMA 是设备 DMA 的地基

  • GPU 帧缓冲 / CUDA :GPU 的显存管理(cudaMalloc 走 UVA,背后是 GUP pin + 大页),而集成 GPU、摄像头、编解码器这类"要物理连续缓冲区"的设备,靠 CMA 兜底。
  • DPDK / 网络:DPDK 要 hugepage 连续内存,某些场景也走 CMA。
  • 与 IOMMU 的分工 :IOMMU(IOMMU 篇)能把不连续的物理页映射成连续的 IOVA,让设备"看起来"连续------有了 IOMMU,很多设备就不需要 CMA 了。但没有 IOMMU(或为了低延迟直通)的场景,CMA 的物理连续仍是刚需。两者是"软件重映射"和"硬件真连续"两条路。

7.2 记住三点

  1. CMA = 预留 + 借用 + 腾出 :启动预留 MIGRATE_CMA 区(cma_declare_contiguous_nid cma.c:239),平时让 movable 页借用(不浪费内存),设备要用时迁走 movable 页腾出连续区。只借给 movable,因为 unmovable 搬不动(#9)。

  2. 分配 = bitmap 找位 + alloc_contig_range 腾区 :dma_alloc_contiguous(contiguous.c:357)→ cma_alloc(cma.c:429)用 bitmap 找连续空闲位 → alloc_contig_range(page_alloc.c:6109)四步腾区:start_isolate_page_range(:6149)隔离 → drain_all_pages 清缓存 → __alloc_contig_migrate_range(:6030)迁 movable 页 → isolate_freepages_range(:6217)摘连续页。

  3. 复用 compaction 引擎 :__alloc_contig_migrate_range 注释明说"based on compact_zone()",用 isolate_migratepages_range + migrate_pages(MR_CONTIG_RANGE)迁页------compaction(#9)、NUMA 迁移(#14)、CMA 三者共用 migrate_pages。释放 cma_release(:560)把页还 buddy、清 bitmap,回到可借用状态。


附:本篇关键源码索引

符号 位置
enum migratetype(MIGRATE_UNMOVABLE/MOVABLE/CMA) include/linux/mmzone.h:45(:46 / :47 / :62)
struct cma(base_pfn + count + bitmap + order_per_bit) mm/cma.h:13
cma_declare_contiguous_nid / cma_declare_contiguous mm/cma.c:239 / include/linux/cma.h:39
cma_alloc(bitmap 找位 + 腾区) mm/cma.c:429
cma_release(还 buddy + 清 bitmap) mm/cma.c:560
dma_alloc_contiguous(设备分配入口) kernel/dma/contiguous.c:357
cma_alloc_aligned(size→页数/align 换算) kernel/dma/contiguous.c:335
alloc_contig_range(四步腾区) mm/page_alloc.c:6109
__alloc_contig_migrate_range(复用 compact_zone) mm/page_alloc.c:6030
start_isolate_page_range(隔离 pageblock 为 MIGRATE_ISOLATE) mm/page_isolation.c:528
isolate_freepages_range(摘出连续空闲页) mm/compaction.c:722
migrate_pages(迁移引擎,接 #9) mm/migrate.c:1885
相关推荐
测试界的小码农1 小时前
【Linux 命令实战(01):认识 Linux 终端,从零掌握第一个命令】
linux·运维·服务器
布裘1 小时前
【银河麒麟】重启后时区丢失?排查发现 localtime 被业务程序替换成硬链接
linux·运维·网络
zhikouai2 小时前
把外部助手接进聊天软件的架构分层与参数配置
服务器·网络·php
huainingning2 小时前
锐捷10.X路由器版本升级不生效问题排查
运维·网络·智能路由器
荣合技术服务3 小时前
HPC 超算集群故障维修实录:找荣合科算维护后,模拟仿真计算又能跑了
运维·服务器·超算服务器·荣合科算
GeW4 小时前
高端化转型进入“补底层”阶段:Linux与数据库的再定位
linux
silent5 小时前
龙芯3B6000M运行Yolov8+FastApi
linux·loongarch·loongnix·龙芯
西西弗Sisyphus6 小时前
理解 Linux 动态库加载:LD_LIBRARY_PATH
linux
AR-26710-6 小时前
Linux Day31——实操启停服务改端口重启
linux·运维