数据库修仙秘境篇五——linux巨页内存编程

Linux内核:内存管理——默认页大小 过小的页面大小会带来较大的页表项增加寻址时 TLB(Translation lookaside buffer)的查找速度和额外开销,但是也会减少程序中的内存碎片,提高内存的利用率;过大的页面大小会浪费内存空间,造成内存碎片,降低内存的利用率,但是可以减少进程中的页表项以及 TLB 的寻址时间;这种类似的场景在我们做系统设计时也比较常见,举一个不是特别恰当的例子,当我们想要在集群上部署服务时,每个节点上的资源是有限的,单个服务占用的资源可能会影响集群的资源利用率或者系统的额外开销。 阅读详情

linux巨页内存指北

巨页的实现,涉及到两个模块:hugetlb和hugetlbfs。

  • hugetlb

    struct hstate hstates[HUGE_MAX_HSTATE];
    上面定义了一个hstate数组,每个元素是一个巨页池。不同的巨页池,其巨页尺寸是不一样的,例如2M的,4M的,1G的等等。
    系统中可能会有多个巨页池,每一个池的巨页尺寸都是不一样的。
    max_hstate标识当前有多少个hstate,即数组的前多少个元素是有效的。默认的话,hugetlb_init中会创建一个hstate,其page size是默认大小,此hstate也就成了默认的hstate。如果hugetlb.c被编译进内核,并且内核启动的时候,命令行参数中有hugepagesz=选项。那么就会调setup_hugepagesz进行处理,setup_hugepagesz应该会在hugetlb_init之前执行。setup_hugepagesz中会调用hugetlb_add_hstate添加一个hstate,其pagesize大小为命令行参数中指定的大小。每一个hstate,在/sys/kernel/mm/hugepages下面会有一个目录与之对应。通过读写此目录下的文件,即可实现对此hstate的各种属性的查看与修改。例如,可以查看或修改此hstate的页面数量。
    例如,下面的命令将2M巨页池的页面数设置为N
    echo N > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
    如果N小于当前池中的页面数量,则会归还相应的页面给内核。如果N为0,就全还给内核了。但是,必须等程序释放了内存,这些内存才会真正还给内核。
    如果程序还没释放,则这种需要释放还没释放的页面数,可以通过如下文件得知。
    /sys/kernel/mm/hugepages/hugepages-2048kB/surplus_hugepages

    当前系统具体是什么参数,可以在host上查看:cat /proc/cmdline

  • hugetlbfs

    hugetlbfs在加载时,会向内核注册hugetlbfs文件系统,并mount hugetlbfs文件系统到内核中,结果保存到hugetlbfs_vfsmount中。这个mount,没有使用什么参数,因此对应到默认的hstate。

概念

  • Page Table: page table也就是一种用于内存管理的实现方式,用于物理地址到虚拟之间的映射。因此对于内存的访问,先是访问Page Table,然后根据Page Table 中的映射关系,隐式的转移到物理地址来存取数据。
  • TLB: Translation Lookaside Buffer (TLB) ,CPU中的一块固定大小的cache,包含了部分page table的映射关系,用于快速实现虚拟地址到物理地址的转换。
  • hugetlb: hugetlb 是TLB中指向HugePage的一个entry(通常大于4k或预定义页面大小)。 HugePage 通过hugetlb entries来实现,也可以理解为HugePage 是hugetlb page entry的一个句柄
  • hugetlbfs: 一个类似于tmpfs的新的in-memory filesystem,在2.6内核被提出

基本操作

[root@develop ~]# grep Huge /proc/meminfo    
AnonHugePages:     14336 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
~# ls /sys/kernel/mm/hugepages/
hugepages-1048576kB  hugepages-2048kB  hugepages-32768kB  hugepages-64kB

大页内存free为0

使用如下方式重新挂载:

# Build DPDK target.
cd dpdk_folder

# Get the hugepage size.
awk '/Hugepagesize/ {print $2}' /proc/meminfo

# Get the total huge page numbers.
awk '/HugePages_Total/ {print $2} ' /proc/meminfo

# Unmount the hugepages.
umount `awk '/hugetlbfs/ {print $2}' /proc/mounts`

# Create the hugepage mount folder.
mkdir -p /mnt/huge

# Mount to the specific folder.
mount -t hugetlbfs nodev /mnt/huge

命令行设置大页内存

$ sysctl -w vm.nr_hugepages=512
$ sysctl -p 

巨页的使用

有两种方式,mmap方式和共享内存方式(shmget/shmat)。
但是,无论是通过哪种方式,最终都是通过对一个hugetlbfs类型的文件做内存映射而实现的(通过file->f_op->mmap完成)。

mmap

这种方式,需要先通过如下命令mount一个hugetlbfs文件系统,通过pagesize指定页面大小。

mount -t hugetlbfs none /mnt/path/to/hugetlbfs -o pagesize=2048K

这样的话,新挂载的文件系统,与页面大小为2048K的hstate相关联。接下来,在/mnt/path/to/hugetlbfs下面创建文件,然后打开文件并通过mmap进行内存映射即可

在编程时通过mmap来映射巨页,在这之前需保证有空闲的巨页可以使用。

# 查看时否有空闲巨页
grep Huge /proc/meminfo
# 此时没有巨页,需要进行配置
[root@localhost ~]# grep Huge /proc/meminfo
AnonHugePages:     14336 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
# 配置巨页,这里设置可用的巨页数为16(此处为虚拟机设置)
echo 16 > /proc/sys/vm/nr_hugepages
# 物理机
echo 16 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

使用如下方式将巨页映射到本进程:

#include <sys/mman.h>
#include <stdio.h>
#include <memory.h>
 
int main(int argc, char *argv[]) {
  char *m;
  size_t s = (8UL * 1024 * 1024);
 
  m = mmap(NULL, s, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS | 0x40000 /*MAP_HUGETLB*/, -1, 0);
  if (m == MAP_FAILED) {
    perror("map mem");
    m = NULL;
    return 1;
  }
 
  memset(m, 0, s);
 
  printf("map_hugetlb ok, press ENTER to quit!\n");
  getchar();
 
  munmap(m, s);
  return 0;
}

其测试demo.c如下:

#include <sys/mman.h>
#include <stdio.h>
#include <memory.h>

#define MB_1 (1024*1024)
#define MB_8 (8*MB_1)

char *a;

void init_hugetlb_seg()
{
  size_t s = MB_8;
 
  a = mmap(NULL, s, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS | 0x40000 /*MAP_HUGETLB*/, -1, 0);
  if (a == MAP_FAILED) {
    printf("map mem failed\n");
    a = NULL;
    exit(-1);
  }
}

void wr_to_array()
{
  int i;
  memset(a, 0, s);
  for( i=0 ; i<MB_8 ; i++) {
    a[i] = 'A';
  }
}

// 按字节读取8M的内存,并统计‘A’和写入的个数是否相等
// 相等则读取成功,不相等则读取失败
void rd_from_array()
{
  int i, count = 0;
  for( i=0 ; i<MB_8 ; i++)
    if (a[i] == 'A') count++;
  if (count==i)
    printf("HugeTLB read success :-)\n");
  else
    printf("HugeTLB read failed :-(\n");
}

int main(int argc, char *argv[])
{
  // 申请内存
  init_hugetlb_seg();
  printf("HugeTLB memory segment initialized !\n");
  printf("Press any key to write to memory area\n");
  getchar();
  // 写入测试数据
  wr_to_array();
  printf("Press any key to rd from memory area\n");
  getchar();
  // 读取测试数据
  rd_from_array();
  printf("Press any key to free memory area\n");
  getchar();
  // 释放内存
  munmap(a, MB_8);
  return 0;
}

针对以上四步分别查看大页内存的使用情况:

  • 申请内存

    [root@localhost ~]# grep Huge /proc/meminfo
    AnonHugePages:     16384 kB
    HugePages_Total:      16
    HugePages_Free:       16
    HugePages_Rsvd:        4
    HugePages_Surp:        0
    Hugepagesize:       2048 kB
    

    申请内存后会阻塞等待输入字符,此时另起一个终端查看巨页情况。可以看到系统保留了4个2048kb的巨页,刚好对应申请的8M内存。

  • 写入测试数据

    随意按下一个字符后开始写入测试数据,写入完成后会再次阻塞等待输入字符。此时巨页情况如下所示:

    [root@localhost ~]# grep Huge /proc/meminfo
    AnonHugePages:     16384 kB
    HugePages_Total:      16
    HugePages_Free:       12
    HugePages_Rsvd:        0
    HugePages_Surp:        0
    Hugepagesize:       2048 kB
    

    可以看到4个2048kb的巨页已经被使用,free的仅剩下12个。

  • 读取测试数据

    随意按下一个字符后开始读取测试数据,读取完成后会再次阻塞等待输入字符。此时巨页情况如下所示:

    [root@localhost ~]# grep Huge /proc/meminfo
    AnonHugePages:     16384 kB
    HugePages_Total:      16
    HugePages_Free:       12
    HugePages_Rsvd:        0
    HugePages_Surp:        0
    Hugepagesize:       2048 kB
    

    此时巨页为发生变化,且读取数据均为写入数据。

  • 释放内存

    随意按下一个字符后开始释放内存,释放完成后进程退出。此时巨页情况如下所示:

    [root@localhost ~]# grep Huge /proc/meminfo
    AnonHugePages:     16384 kB
    HugePages_Total:      16
    HugePages_Free:       16
    HugePages_Rsvd:        0
    HugePages_Surp:        0
    Hugepagesize:       2048 kB
    

    可以发现巨页个数又恢复到了最开始配置的16个。

shmget

shmget属于XSI共享内存,是X/Open组织对UNIX定义的一套接口标准(X/Open System Interface)。其底层实现与mmap一致。

在编程时通过shmget来访问巨业,在这之前需保证有空闲的巨页可以使用。

# 查看时否有空闲巨页
grep Huge /proc/meminfo
# 此时没有巨页,需要进行配置
[root@localhost ~]# grep Huge /proc/meminfo
AnonHugePages:     14336 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
# 配置巨页,这里设置可用的巨页数为16(此处为虚拟机设置)
echo 16 > /proc/sys/vm/nr_hugepages
# 物理机
echo 16 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

按照如下命令设置巨页后,因为我们的巨页页面大小为2048kb(2M),设置了16个页面后,我们可以使用32M内存。

要使用巨页,需要把巨页内存attach到当前进程内。实现代码如下:

#define MB_1 (1024*1024)
#define MB_8 (8*MB_1)

char *a;
int shmid1;

void init_hugetlb_seg()
{
  // 2是共享内存key,用于标识内存,可随意设置
  // SHM_HUGETLB是基于大页内存创建共享内存的标志
  shmid1 = shmget(2, MB_8, SHM_HUGETLB 
         | IPC_CREAT | SHM_R /* 创建并具有读写权限*/
         | SHM_W);
  if ( shmid1 < 0 ) {
    perror("shmget");
    exit(1);
  }
  printf("HugeTLB shmid: 0x%x\n", shmid1);
  // 将内存attach到进程,后面基于地址a进行大页内存操作
  a = shmat(shmid1, 0, 0);
  if (a == (char *)-1) {
    perror("Shared memory attach failure");
    shmctl(shmid1, IPC_RMID, NULL);
    exit(2);
  }
}

上面即获取到了大页内存的起始地址,可以根据该地址和内存长度实现内存池。

下面是具体的巨页内存使用demo.c:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>

#define MB_1 (1024*1024)
#define MB_8 (8*MB_1)

char  *a;
int shmid1;

void init_hugetlb_seg()
{
  // 2是共享内存key,用于标识内存,可随意设置
  // SHM_HUGETLB是基于大页内存创建共享内存的标志
  shmid1 = shmget(2, MB_8, SHM_HUGETLB 
         | IPC_CREAT | SHM_R /* 创建并具有读写权限*/
         | SHM_W);
  if ( shmid1 < 0 ) {
    perror("shmget");
    exit(1);
  }
  printf("HugeTLB shmid: 0x%x\n", shmid1);
  // 将内存attach到进程,后面基于地址a进行大页内存操作
  a = shmat(shmid1, 0, 0);
  if (a == (char *)-1) {
    perror("Shared memory attach failure");
    shmctl(shmid1, IPC_RMID, NULL);
    exit(2);
  }
}

// 对申请的8M大页内存按字节每字节都写入字符‘A’:
void wr_to_array()
{
  int i;
  for( i=0 ; i<MB_8 ; i++) {
    a[i] = 'A';
  }
}

// 按字节读取8M的内存,并统计‘A’和写入的个数是否相等
// 相等则读取成功,不相等则读取失败
void rd_from_array()
{
  int i, count = 0;
  for( i=0 ; i<MB_8 ; i++)
    if (a[i] == 'A') count++;
  if (count==i)
    printf("HugeTLB read success :-)\n");
  else
    printf("HugeTLB read failed :-(\n");
}

int main(int argc, char *argv[])
{
  // 申请内存
  init_hugetlb_seg();
  printf("HugeTLB memory segment initialized !\n");
  printf("Press any key to write to memory area\n");
  getchar();
  // 写入测试数据
  wr_to_array();
  printf("Press any key to rd from memory area\n");
  getchar();
  // 读取测试数据
  rd_from_array();
  printf("Press any key to free memory area\n");
  getchar();
  // 释放内存
  shmctl(shmid1, IPC_RMID, NULL);
  return 0;
}
gcc demo.c -o demo

针对以上四步分别查看大页内存的使用情况:

  • 申请内存

    [root@localhost ~]# grep Huge /proc/meminfo
    AnonHugePages:     16384 kB
    HugePages_Total:      16
    HugePages_Free:       16
    HugePages_Rsvd:        4
    HugePages_Surp:        0
    Hugepagesize:       2048 kB
    

    申请内存后会阻塞等待输入字符,此时另起一个终端查看巨页情况。可以看到系统保留了4个2048kb的巨页,刚好对应申请的8M内存。

  • 写入测试数据

    随意按下一个字符后开始写入测试数据,写入完成后会再次阻塞等待输入字符。此时巨页情况如下所示:

    [root@localhost ~]# grep Huge /proc/meminfo
    AnonHugePages:     16384 kB
    HugePages_Total:      16
    HugePages_Free:       12
    HugePages_Rsvd:        0
    HugePages_Surp:        0
    Hugepagesize:       2048 kB
    

    可以看到4个2048kb的巨页已经被使用,free的仅剩下12个。

  • 读取测试数据

    随意按下一个字符后开始读取测试数据,读取完成后会再次阻塞等待输入字符。此时巨页情况如下所示:

    [root@localhost ~]# grep Huge /proc/meminfo
    AnonHugePages:     16384 kB
    HugePages_Total:      16
    HugePages_Free:       12
    HugePages_Rsvd:        0
    HugePages_Surp:        0
    Hugepagesize:       2048 kB
    

    此时巨页为发生变化,且读取数据均为写入数据。

  • 释放内存

    随意按下一个字符后开始释放内存,释放完成后进程退出。此时巨页情况如下所示:

    [root@localhost ~]# grep Huge /proc/meminfo
    AnonHugePages:     16384 kB
    HugePages_Total:      16
    HugePages_Free:       16
    HugePages_Rsvd:        0
    HugePages_Surp:        0
    Hugepagesize:       2048 kB
    

    可以发现巨页个数又恢复到了最开始配置的16个。

通过对比可以发现,mmap的接口比shmget要更加简洁。

reference

  1. https://blog.youkuaiyun.com/zhang123456456/article/details/77853345
  2. https://blog.youkuaiyun.com/weixin_35664258/article/details/83348133
  3. https://www.cnblogs.com/zfox2017/p/6794617.html
  4. https://blog.youkuaiyun.com/crazycoder8848/article/details/44983265
  5. https://blog.youkuaiyun.com/weixin_30363509/article/details/96763008?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_default&utm_relevant_index=1
  6. https://www.cnblogs.com/xianzhedeyu/p/5784105.html
SqlServer容器化运维:不用SSMS也能玩转bak还原(命令行终极方案) 本文详细介绍了在Docker容器化环境中,如何通过命令行实现SQL Server数据库的bak文件还原,特别适用于无GUI的Linux服务器和CI/CD场景。从环境准备、备份文件传输到完整的命令行还原流程,提供了实用技巧和自动化脚本方案,帮助开发者高效完成数据库运维工作。 阅读详情

相关推荐

C++工业级开发九重修炼:从现代语法到系统架构实战

C++作为一门接近系统底层的编程语言,其核心价值在于提供零成本抽象和对硬件的直接掌控力,从而实现无与伦比的运行时性能。其原理建立在资源获取即初始化的RAII哲学之上,通过智能指针、移动语义等机制,将资源生命周期与对象生命周期绑定,确保了异常安全和内存安全。这种精细的控制能力,使其在需要极致性能与稳定性的技术领域具有不可替代的价值,广泛应用于游戏引擎、高频交易系统、嵌入式设备和大型分布式后台等场景。现代C++标准引入了模块、协程、概念等新特性,持续演进着开发范式,而像CMake这样的现代构建系统和vcpkg等

lvwenwen 475

hugetlbfs的使用测试

hugetlbfs CPU缓存中有一组缓存专门用于缓存TLB,但其大小是有限的。当采用的默认页面大小为 4KB,其产生的TLB较大,因而将会产生较多 TLB Miss 和缺页中断,从而大大影响应用程序的性能。操作系统以 2MB 甚至更大作为分页的单位时,将会大大减少 TLB Miss 和缺页中断的数量,显著提高应用程序的性能。这也正是 Linux 内核引入大页面支持的直接原因。好处是很明显的,假设应用程序需要 2MB 的内存,如果操作系统以 4KB 作为分页的单位,则需要 512 个页面,进而在 TL

weixin_48101150的博客 4618

独立游戏开发的四层地基与能力测绘方法论

独立游戏开发本质上是个人工程能力与创作意图的系统性对齐过程。其核心不在于工具堆砌或AI套用,而在于对时间投入、认知深度与执行精度的三重能力测绘;技术栈选择需以环境稳定性为前提,Godot等轻量引擎因其低耦合、易版本化特性成为2D/文字类项目的理想载体;资源生产须构建人机协同的标准化流水线,避免AI生成的‘伪可用’陷阱;验证闭环强调‘早、小、频’的真实用户反馈,将MVE(最小可行体验)作为比MVP更本质的起点。本文聚焦从零启动的独立开发者如何夯实目标锚定、技术固化、资源生产与反馈验证四层地基,实现从保安笔记本

weixin_34416754的博客 491

Linux内核巨页代码解析和使用

前言 巨页的实现,涉及到两个模块:hugetlb 和 hugetlbfs。 hugetlb 相当于是 huge page 页面管理者,页面的分配及释放,都由此模块负责。 hugetlbfs 则用于向用户提供一套基于文件系统的巨页使用界面,其下层功能的实现,则依赖于 hugetlb。 目录 1、hugetlb模块 2、hugetlbfs模块 3、使用巨页 3.1、 mmap方式 3.2...

3593

Linux内存管理(9):HugePage

巨页文件系统(HUGETLBFS)、透明巨页(Transparent HugePage, THP)

zhang_shuaifeng的博客 673

【CGroup原理篇V1】十、HugeTLB子系统

HugeTLB控制器可以在cgroup文件系统被挂载的时候被创建。

从0到1,突破自己 1216

数据库修仙秘境篇三——linux内存管理指北

linux内存管理指北 内存是一段连续的地址单元,linux内核接管内存管理后,会将内存划分为内核区和用户区。因而内存管理就分为两个层面: 内核内存管理 一般是kmalloc(小块内存)和vmalloc(大块内存)。 用户内存管理 一般是malloc(小块内存)和mmap(大块内存)。 本文内容大量摘抄引用自Mortree的博客和CodingLabs博客,这里只是做了简单的整理。详细内容请阅读他们的博客。 内存分类 相对于进程来说,内存分为如下几个部分: 堆 栈 数据段 代码段 bss段 当

growdu的网络博客 214

Kali Linux 修仙全录:从凡人到网络安全金仙的修炼之路

今日我以神通护网络,他朝仗剑守乾坤——此为Kali修仙者的天道誓言。

探索云原生与智能化驱动下的安全运维新范式。关注DevSecOps、可观测性、AIOps等前沿领域,与您共赴技术前沿。 176

数据库修仙秘境篇五——linux cache指北

linux cache指北 cache是什么 计算机中数据存取满足“二八定律”(局部性原理),为了以较低的成本大幅提高性能,现代cpu都有cache。cpu cache已经发展到了三级缓存结构,基本上现在买的个人电脑都是L3结构。其中L1和L2cache为每个核独有,L3则所有核共享。 本文内容大量摘抄自飘舞的雪的博客,详情请参阅原文。 cache bouncing 为了保证所有的核看到正确的内存数据,一个核在写入自己的L1 cache后,CPU会执行Cache一致性算法把对应的cacheline(一般是

growdu的网络博客 574

异步bus交互(一)— 两级DFF同步器

异步bus交互(一)— 两级DFF同步器 跨时钟域处理 & 亚稳态处理 1.问题产生 现在的芯片(比如SOC,片上系统)集成度和复杂度越来越高,通常一颗芯片上会有许多不同的信号工作在不同的时钟频率下。比如SOC芯片中的CPU通常会工作在一个频率上,总线信号(比如DRAM BUS)会工作在另一个时钟频率下,而普通的信号又会工作在另外的时钟频率下。这3个不同时钟频率下工作的信号往往需要相互沟通和传递信号。 不同时钟域下的信号传递就涉及到跨时钟域信号处理,因为相互之间的频率、相位不一样,如果不做处理或者

qq_44816673的博客 5121

SPEI计算避坑指南:gma中Distribution和FitMethod参数怎么选?

本文深入探讨了在SPEI计算中如何科学选择gma库中的Distribution和FitMethod参数,帮助研究者避开常见陷阱。详细分析了LogLogistic、Gamma和Pearson3三种分布的适用场景,以及LMoment与MLE拟合方法的优缺点,为气象干旱研究提供实用指南。

weixin_30308101的博客 254

数据库修仙秘境篇四——linux锁指北

linux锁指北 锁一般用于解决资源竞争,比如多进程或者多线程场景下。锁主要是为了保证同一个资源在同一时间只能被一名修改者修改。 互斥锁(mutex) 对于竞争资源来说,只要有一方获取了资源的锁,另一方就无法修改竞争资源,需要等待锁释放并获取到锁之后才能进行修改。 有两种方式创建互斥锁: 静态创建 POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER 来静态初始化互斥锁,方法如下: pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

growdu的网络博客 672

ANSYS HFSS 中的相控天线阵列仿真方法

相控天线阵列系统广泛使用,从国防雷达应用到商业 5G 应用。设计这些天线阵列涉及复杂的数学运算,需要全波仿真。Ansys HFSS 全场 3D 电磁仿真软件可以在合理的时间内以较低的计算成本仿真复杂的相控阵天线系统,同时考虑复杂激励、环境(即附近的天线)和平台对其性能的影响。本博客介绍了可用于有效仿真相控天线阵列的不同方法。以下是不同仿真方法的简要概述,视频链接中提供了完整的演示。ANSYS HFSS 提供 4 种不同的相控天线阵列仿真方法:1) 晶胞-无限阵列。

jkh920184196的博客 4257

数据库修仙秘境篇一——不得不知道的linux库的装载、链接

不得不知道的linux库的装载、链接

growdu的网络博客 421

蛋白质组学进阶指南 | (八)差异蛋白筛选与功能解析实战

本文是蛋白质组学差异蛋白筛选与功能解析的实战指南。详细讲解了如何利用R语言的limma包进行差异表达分析,结合FDR校正和差异倍数设定筛选关键蛋白,并通过火山图可视化结果。进一步介绍了使用clusterProfiler进行GO与KEGG功能富集分析,以及利用STRING数据库和Cytoscape构建蛋白互作网络以识别枢纽分子,最终串联分析形成可验证的生物学假说。

weixin_29208077的博客 745

Central Finance 全景解析:用 SAP S/4HANA 构建跨系统的财务中台与渐进式转型路径

Central Finance 是基于 SAP S/4HANA 的一种部署与应用场景:在不打断现有异构源系统运营的前提下,把多套 SAP 与非 SAP 系统中的财务与管理会计数据实时/准实时复制到一套中心化的 SAP S/4HANA 中,作为统一的记账与分析底座,逐步把选定的财务流程(如预算控制、付款、固定资产结账等)迁入中心系统。这让企业既能快速获得统一报表与统一核算结构,又为未来的整体迁移留出了弹性路径。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 393

数据库修仙金丹篇八——dpdk之kni使用

dpdk之kni使用 什么是kni Kni(Kernel NIC Interface)内核网卡接口,是DPDK允许用户态和内核态交换报文的解决方案,模拟了一个虚拟的网口,提供dpdk的应用程序和linux内核之间通讯。kni接口允许报文从用户态接收后转发到linu协议栈去。 为什么要弄一个kni接口,虽然dpdk的高速转发性能很出色,但是也有自己的一些缺点,比如没有协议栈就是其中一项缺陷,当然也可能当时设计时就将没有将协议栈考虑进去,毕竟协议栈需要将报文转发处理,可能会使处理报文的能力大大降低。 当k

growdu的网络博客 7739

node运行项目-Network: unavailable-没有ip地址

vscode运行vue项目后发现Network: unavailable 是什么情况呢?可能有一下三种情况:1.多个网卡原因:打开网络共享中心,把多余的网络禁用掉,只留一个2.在中配置host及public3.系统环境变量问题。

JackieDYH的博客 7540

Linux的修仙之路——安装和基本命令

Linux的安装和基本命令Linux的安装Linux由来Linux的组成部分Linux现行发行版本VMware安装LinuxLinux的基本命令浏览目录、文件类命令系统信息类命令进程管理类命令软件包管理命令其他常用命令Linux的配套练习 Linux的安装 Linux由来 初显身手的Linux Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统。伴随着互联网的发展,Linux得到了来自全世界软件爱好者、组织、公司的支持。它除

ningsheng的博客 2988

1、深入解析OTA/gm - C滤波器架构与设计

本文深入探讨了OTA/gm-C滤波器的架构与设计方法,涵盖了从基本构建模块到高阶滤波器实现的多种技术。重点分析了双积分器环路结构(如Tow-Thomas和KHN滤波器)的工作原理、性能特点及OTA非理想特性对滤波器的影响,并介绍了降低寄生效应、提升动态范围的方法。文章还讨论了基于LC梯形仿真、多环反馈和电流模式的gm-C滤波器设计,以及自动调谐技术在频率稳定性中的应用。最后总结了不同类型gm-C滤波器的优缺点及其适用场景,为高频集成连续时间滤波器的设计提供了全面的技术参考。

fanta的博客 187

深度强化学习 | 基于SAC算法的动态避障(ROS C++仿真)

本文介绍了基于SAC(软性演员-评论家)算法的机器人运动规划方法,通过PyTorch框架实现了端到端训练,并部署到Python和ROS C++中。实验结果显示,基于SAC算法的智能体在动态避障任务中表现良好,能实现从起点到终点的无碰撞导航。

FRIGIDWINTER的博客 8217

跨界内容生成系统:从拓扑算法到修仙规则引擎的技术实现

规则引擎作为现代软件系统的核心组件,通过定义和执行业务逻辑来实现复杂的决策流程。其技术原理基于条件判断和动作执行的组合,能够将抽象的业务需求转化为可执行的代码逻辑。在技术价值层面,规则引擎提供了高度的灵活性和可维护性,使系统能够快速适应需求变化。特别是在游戏开发和内容生成领域,规则引擎的应用尤为广泛,能够处理复杂的角色属性计算、环境交互逻辑和随机事件生成。以拓扑算法为例,这种数学概念可以转化为游戏中的关卡生成机制,通过连通性分析和空间变换创造多样化的游戏体验。结合修仙题材的设定系统,规则引擎能够实现境界提升

weixin_34087307的博客 348

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

大数据生态系统 修仙之道 Linux Blog

大数据生态系统 修仙之道 Linux Blog @(2019-01-03)[Docs Language:简体中文 &amp; English|Programing Language:Linux|Website:www.geekparkhub.com||GeekDeveloper:JEEP-711|Github:github.com/geekparkhub|Gitee:gitee.com/geekp...

JEEP/711 Blog 612

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Java开发实战:从环境配置到内存管理的核心避坑指南

在软件开发领域,环境配置与运行时管理是构建稳定应用的基础。理解环境变量的原理,如JAVA_HOME与PATH的协同机制,能确保开发工具链的正确识别与调用。内存管理则是程序性能与稳定性的核心,JVM通过堆内存分配与垃圾回收机制自动管理对象生命周期,但不当的编码实践可能导致内存泄漏或溢出错误,深刻理解其原理对编写高效、健壮的代码至关重要。这些基础技术广泛应用于企业级应用开发、后端服务构建等场景。本文聚焦Java开发中环境变量配置、版本兼容性、内存不足(OutOfMemoryError)及数组越界等典型问题的深度

weixin_34115824的博客 297

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

从网络工程师视角解析系统思维:感知、连接与逆向工程在技术实践中的应用

系统思维与问题建模是工程师解决复杂问题的核心能力。其原理在于将抽象系统分解为可观测、可交互的组件,通过定义清晰的接口和协议实现控制与通信。这种思维模式的技术价值在于提供了一套通用的问题分析与解决框架,能够跨越不同领域应用。在工程实践中,它广泛应用于网络故障排查、系统性能优化、安全协议分析以及自动化运维等场景。例如,网络感知与扫描技术(如使用airodump-ng进行无线网络发现)体现了系统信息收集的思维;而协议分析与流量逆向工程则是理解系统行为、进行调试与二次开发的基础。掌握这种从感知到分析,再到干预的完整

weixin_30629653的博客 360

迷雾

序言    迷雾森林,适合修仙的季节。。。    风去风又来,会或者不会,灵感乍现的一瞬间。。。聊聊最近所感。。。风言风语    断断续续看了半年的书,突然发现这些书里并...

运维Linux和python 449
上一篇: 数据库修仙金丹篇六——vpp与dpdk的关系
下一篇: 数据库修仙金丹篇八——dpdk之kni使用
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我在数据库世界里修仙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值