linux内存调节之CMA

2023-11-19

本文贴代码过头了,以后想起来再优化一下吧

目录

概述

数据结构

构建初始化(DTS+CONFIG_DMA_CMA)

页表与物理页初始化

分配器激活

分配器使用

CMA部署

实战


概述

CMA(Contiguous Memory Allocator)是连续内存分配技术,是 Linux Kernel 内存管理系统的扩展,目的在于解决视频播放 (特别对于 4K 视频) 等需要预留大量连续内存导致运行内存紧张的问题。

CMA 框架的主要作用不是分配内存,而是解析和管理内存配置,以及作为在设备驱动程序和可插拔的分配器之间的中间组件。

 

数据结构

1 . struct cma 结构用于维护一块 CMA 区域

struct cma {

unsigned long   base_pfn; //CMA 区域 起始物理地址对应的物理页帧号

unsigned long   count; //描述 CMA 区域总共维护的 page 数量

unsigned long   *bitmap; //该 CMA 区域的所有物理页维护在该 bitmap 中,bitmap 中每个 bit 代表一定数量的物理页,至于代表多少物理页与 order_per_bit 有关

unsigned int order_per_bit; //指明该 CMA 区域的 bitmap 中,每个 bit 代表 的 page 数量

struct mutex    lock;

const char *name; //CMA 区域的名字

};

cma模块使用bitmap来管理其内存的分配,0表示free,1表示已经分配。具体内存管理的单位和struct cma中的order_per_bit成员相关,如果order_per_bit等于0,表示按照一个一个page来分配和释放,如果order_per_bit等于1,表示按照2个page组成的block来分配和释放,以此类推。struct cma中的bitmap成员就是管理该cma area内存的bit map。count成员说明了该cma area内存有多少个page。它和order_per_bit一起决定了bitmap指针指向内存的大小。base_pfn定义了该CMA area的起始page frame number,base_pfn和count一起定义了该CMA area在内存在的位置。

 

2 . 维护 CMA 分配器中可用的 CMA 区域。 每个 CMA 区域包含了一段可用的物理内存

#define MAX_RESERVED_REGIONS 32

struct cma cma_areas[MAX_CMA_AREAS];

每一个struct cma抽象了一个CMA area,标识了一个物理地址连续的memory area。调用cma_alloc分配的连续内存就是从CMA area中获得的。默认定义32个cma_areas。

 

构建初始化(DTS+CONFIG_DMA_CMA)

CMA的分配初始化有三种:一种DTS,一种Kbuild配置,还一种通过cmdline常见。此处分析优先级最高的DTS方式。使用DTS方式时,要打开CONFIG_DMA_CMA宏,否则只会创建预留区,不会将改预留区加入到CMA中。

 

start_kernel

---->setup_arch

             ---->arm_memblock_init

                     --→early_init_fdt_scan_reserved_mem

void __init early_init_fdt_scan_reserved_mem(void) {

    int n;

    u64 base, size;

    early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
                fdt_totalsize(initial_boot_params), 0);


    //遍历DTS中的节点,然后把节点信息传入__fdt_scan_reserved_mem函数,该函数用于筛选“reserved-memory”节点,然后将信息存储在reserved_mem数组里

    of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);


    //将预留区中的区域在 MEMBLOCK 分配之后加入到 CMA 和 DMA 区域中

    fdt_init_reserved_mem();

}

为 DTS 中的预留区分配内存。 DTS 中预留区分做两类,一类是 DTB 本身需要预留的区域,另一类是 “/reserved-memory” 节点中描述的预留区。在后者中,预留区分配需要的内存之后,还会将这些预留区加入到 CMA 或 DMA 中

void __init fdt_init_reserved_mem(void) {

    int i;

    for (i = 0; i < reserved_mem_count; i++) {

        struct reserved_mem *rmem = &reserved_mem[i];

        unsigned long node = rmem->fdt_node;

        int len;

        int err = 0;


//将系统预留数组 reserved_mem[] 中 size 成员为 0 的成员分配对应长度的物理内存作为预留区。实现连续物理内存的最初分配,并完成将该区域加入到系统的预留区 数组 reserved-mem[] 中。

//注意:当在dts中指定了size大小,那么这里的rmem->size不为0,无需执行alloc size动作

        if (rmem->size == 0)

            err = __reserved_mem_alloc_size(node, rmem->name, &rmem->base,           &rmem->size);


        //遍历 __reservedmem_of_table
            if (err == 0)

                 __reserved_mem_init_node(rmem);

    }

}

__reserved_mem_init_node函数中一些代码无法追踪,遍历 __reservedmem_of_table section 内的预留区时,函数会调用 rmem_cma_setup() 函数,该函数用于将全局 reserved-mem[] 数组的区域加入到 CMA 分配器中,即添加 一块新的 CMA 区域。在该函数内,涉及从 MEMBLOCK 分配物理内存和加入 新的 CMA 区域,也包含了设置 CMA 分配器使用的默认分配区。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

将预留区添加到 CMA 子系统

static int __init rmem_cma_setup(struct reserved_mem *rmem) {

    phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);

    phys_addr_t mask = align - 1;

    unsigned long node = rmem->fdt_node;

    struct cma *cma;

    int err;


        //包含 “no-map” 或者不包含 “reusable” 属性预留区不建立映射关系

    if (!of_get_flat_dt_prop(node, "reusable", NULL) || of_get_flat_dt_prop(node, "no-map", NULL))

        return -EINVAL;


        //对预留区的 基地址和长度进行对齐检测

    if ((rmem->base & mask) || (rmem->size & mask)) {

        pr_err("Reserved memory: incorrect alignment of CMA region\n");

        return -EINVAL;

    }


       //将预留区 加入到一块可用的 CMA 区域内,并初始化这块 CMA 区域的管理数据结构体成员。【详细见后】

    err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);

      //将预留区加入到 dma_mmu_remap[] 数组,以供系统初始化 DMA 映射时使用

    dma_contiguous_early_fixup(rmem->base, rmem->size);


      //设备数节点含有linux,cma-default属性,则将当前 CMA 区域作为系统设备默认 使用的 CMA 区域

    if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))

        dma_contiguous_set_default(cma);


    rmem->ops = &rmem_cma_ops; //操作方法 【详细见后】

    rmem->priv = cma;

    return 0;

}

RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);

=====================================================================

//cma结构体初始化的同时也指向了当前cma area count的cma_areas全局数组。

int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, int order_per_bit, struct cma **res_cma) {

    struct cma *cma;

    phys_addr_t alignment;

    alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);

    cma = &cma_areas[cma_area_count];

    cma->base_pfn = PFN_DOWN(base);

    cma->count = size >> PAGE_SHIFT;

    cma->order_per_bit = order_per_bit;
    
    *res_cma = cma;

    cma_area_count++;

    totalcma_pages += (size / PAGE_SIZE);

    return 0;

}

================================================================

rmem_cma_ops 包含 rmem_cma_device_init 和 rmem_cma_device_release

前者设置设备使用的 CMA 区域                dev->cma_area = cma;

后者用于将设备预留区信息设置为 NULL dev->cma_area = NULL;

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

至此连续物理内存并未初始成功,只是做出了内存预留。

 

页表与物理页初始化

构建完 CMA 区域之后,CMA 需要将每个 CMA 区域的页表进行映射,以及将 CMA 区域内的物理页进行初始化。该阶段初始化完毕之后还不能使用 CMA 分配器。

start_kernel

→setup_arch

    -→paging_init

        →dma_contiguous_remap

 

该函数用于创建映射关系。【建立映射的套路都是如下代码】

void __init dma_contiguous_remap(void) {

    int i;

    for (i = 0; i < dma_mmu_remap_num; i++) {

        phys_addr_t start = dma_mmu_remap[i].base;

        phys_addr_t end = start + dma_mmu_remap[i].size;

        struct map_desc map;

        unsigned long addr;


        if (end > arm_lowmem_limit) end = arm_lowmem_limit;

        if (start >= end) continue;


        map.pfn = __phys_to_pfn(start);

        map.virtual = __phys_to_virt(start);

        map.length = end - start;

        map.type = MT_MEMORY_DMA_READY;


        for (addr = __phys_to_virt(start); addr < __phys_to_virt(end);

                         addr += PMD_SIZE)

            pmd_clear(pmd_off_k(addr));


        flush_tlb_kernel_range(__phys_to_virt(start), __phys_to_virt(end));


                //建立映射

        iotable_init(&map, 1);


    }


}

 

分配器激活

间接对 CMA 进行激活初始化,激活之后 CMA 就可用供其他模块、设备和子系统使用。

static int __init cma_init_reserved_areas(void) {

    int i;


        //CMA 的激活入口

    for (i = 0; i < cma_area_count; i++) {

        int ret = cma_activate_area(&cma_areas[i]); //【详细见后】

        if (ret) return ret;

    }

    return 0;

}

core_initcall(cma_init_reserved_areas);

=============================================================

函数用于将 CMA 区域内的预留页全部释放添加到 Buddy 管理器内,然后激活 CMA 区域供系统使用。此函数将cam结构体剩余成员的初始化。

static int __init cma_activate_area(struct cma *cma) {


//比如CMA为8M,则bitmap size为2^8

    int bitmap_size = BITS_TO_LONGS(cma_bitmap_maxno(cma)) * sizeof(long);

    unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;

    unsigned i = cma->count >> pageblock_order;

    struct zone *zone;


    cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);

    zone = page_zone(pfn_to_page(pfn));


       //检查 CMA 区域的每个 pageblock 内所有页是否有效,并且所有页与起始页是在同一个 ZONE 分区 内

    do {

        unsigned j;

        base_pfn = pfn;

        for (j = pageblock_nr_pages; j; --j, pfn++) {

            if (page_zone(pfn_to_page(pfn)) != zone)

                goto not_in_zone;

        }


//将 pageblock 内所有的物理页的 RESERVED 标志清除,让后将这些页都返回 给 Buddy 系统使用 【详细见后】

        init_cma_reserved_pageblock(pfn_to_page(base_pfn));

    } while (--i);

    mutex_init(&cma->lock);

    return 0;


not_in_zone:

    pr_err("CMA area %s could not be activated\n", cma->name);

    kfree(cma->bitmap);

    cma->count = 0;

    return -EINVAL;

}

========================================================================

void __init init_cma_reserved_pageblock(struct page *page) {

    unsigned i = pageblock_nr_pages;

    struct page *p = page;


    do {

        __ClearPageReserved(p); //所有 page 清除 Reserved 标志

        set_page_count(p, 0);

    } while (++p, --i);


        //将cma区域 page的迁移类型设置为 MIGRATE_CMA

    set_pageblock_migratetype(page, MIGRATE_CMA);


        //内核中默认pageblock_order = MAX_ORDER-1,可以直接从else看起

    if (pageblock_order >= MAX_ORDER) {

        i = pageblock_nr_pages;

        p = page;

    do {

        set_page_refcounted(p);

        __free_pages(p, MAX_ORDER - 1);

        p += MAX_ORDER_NR_PAGES;

    } while (i -= MAX_ORDER_NR_PAGES);

    } else {

        set_page_refcounted(page);              //page 引用 计数设置为 1

        __free_pages(page, pageblock_order); //释放页

    }


        //将释放的 page 数量全部加到系统里进行维护

    adjust_managed_page_count(page, pageblock_nr_pages);

}

cma默认是从reserved memory中分配的,通常情况这块内存是直接分配并预留不做任何使用,无形之中造成了浪费。所以在不用的时候放入伙伴系统,作为普通内存使用。

 

分配器使用

CMA 激活之后,内核可以使用 CMA API 就可以使用连续物理内存

 

分配 CMA 里面的连续物理内存,可以使用:

struct page *dma_alloc_from_contiguous(struct device *dev, size_t count, unsigned int align, gfp_t gfp_mask)

指针dev 指向需要分配CMA的设备,

参数 count 指明需要分配的page数,

align 参数 指明对齐的方式,align = CONFIG_CMA_ALIGNMENT;

no_warn 控制警告消息的打印。

核心函数cma_alloc:根据pfn获取page

 

当使用完 CMA 连续物理内存之后,可以将物理内存归还给 CMA 内存管理器

bool dma_release_from_contiguous(struct device *dev, struct page *pages, int count)

参数 dev 指向一个设备,

pages 指向连续物理内存的起始页,

参数 count 表示分配的page数

核心函数cma_release:根据page找到pfn,然后根据pfn释放当前分配的页

 

当然还有更高级的接口

cma_allocation_alloc

cma_allocation_free

 

CMA部署

CMA 问题的本质就是如何规划系统的 物理内存

 

第一个比较重要的是获得系统物理内存的范围

cat /proc/iomem

找到 “System RAM”, 其代表系统物理内存的起始物理地址和终止物理地址,分配的cma区域不能超过这段范围。

 

第二个查看当前系统的预留区

系统已经预留的不可使用

cat /sys/kernel/debug/memblock/reserved

通过这个命令可以知道系统已预留的内存信息,这些已预留的内存信息不可使用。但排除这些预留区域,再在RAM范围内找出可用内存,再满足对其需求就可以自己手动找出可用于CMA的区域。

 

第三个,在DTS中说明cma信息

dts方式部署cma的好处是既可以指定起始地址和长度,还可以命名该cma

linux,cma {                                        //cma 名字

        compatible = "shared-dma-pool";            //默认属性

        reusable;                                  //默认属性

        size = <0x00800000>; /* 8M */              //通常size为8M的倍数

        alloc-ranges = <0x69000000 0x00800000>;    //起始地址和长度

        linux,cma-default;                         //默认使用这段区域

};

这些属性可以查看rmem_cma_setup函数

实战

1 查看memory范围

2 查看预留区信息

3 dts添加代码

reserved-memory {

    #address-cells = <1>;

    #size-cells = <1>;

    ranges;

        //此处为要添加的cma。假设为video预留一块8M内存

    video_cma: video_cma@69000000 {

        compatible = "shared-dma-pool";

        reusable;

        reg = <0x69000000 0x800000>;

    };

};

添加完dts信息后,系统在启动阶段会去自动读取并解析。

4 编写驱动

#include <linux/module.h>

#include <linux/init.h>

#include <linux/device.h>

#include <linux/cma.h>

#include <linux/mm.h>

#include <linux/of.h>

#include <linux/dma-contiguous.h>

#include <linux/fs.h>

#include <linux/miscdevice.h>

#include <linux/slab.h>

#include <linux/spinlock.h>

#include <linux/types.h>

#include <linux/uaccess.h>


#include "cma.h"


#define CMA_NAME "video_cma@69000000"


struct cma_allocation {

    struct list_head list;

    struct page *cma_page;

    int count;

    unsigned long vaddr;

};


static struct device *cma_dev;

static LIST_HEAD(cma_allocations);

static DEFINE_SPINLOCK(cma_lock);


/*

 * struct cma *find_cma_by_name(const char *name) {

 *     int idx;

 *     for (idx = 0; idx < MAX_CMA_AREAS; idx++) {

 *         if (!strcmp(name, cma_areas[idx].name))

 *             return &cma_areas[idx];

 *     }

 *     return NULL;

 * }

 */


static ssize_t

cma_test_read(struct file * file, char __user *buf, size_t count, loff_t *ppos)

{

    struct cma_allocation *alloc = NULL;
    
    bool ret;


    spin_lock(&cma_lock);

    if(!list_empty(&cma_allocations)) {

        alloc = list_first_entry(&cma_allocations, struct cma_allocation, list);

        list_del(&alloc->list);

    }

    spin_unlock(&cma_lock);


    if(!alloc)

        return -EIDRM;


    ret = dma_release_from_contiguous(cma_dev, alloc->cma_page, alloc->count);

    if (ret)

        dev_info(cma_dev, "free %d pages. vaddr: 0x%lx paddr: 0x%x\n",     alloc->count, alloc->vaddr, __pa(alloc->vaddr));
    

        kfree(alloc);

        return 0;

    }


static ssize_t

cma_test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)

{

    struct cma_allocation *alloc;

    int ret;


    alloc = kmalloc(sizeof(struct cma_allocation), GFP_KERNEL);

    if(!alloc)

        return -ENOMEM;

    memset(alloc, 0, sizeof(struct cma_allocation));


    ret = kstrtouint_from_user(buf, count, 0, &alloc->count);

    if (ret != 0) {

        pr_notice("copy_from_user failed\n");

        return -EFAULT;

    }


    alloc->cma_page = dma_alloc_from_contiguous(cma_dev, alloc->count, 8, GFP_KERNEL);

    if (!alloc->cma_page) {

        dev_info(cma_dev, "alloc cma pages failed!\n");

        return -EFAULT;

    }

    alloc->vaddr = (unsigned long)page_address(alloc->cma_page);

    if(alloc->vaddr) {

        dev_info(cma_dev, "alloc %d pages, vaddr: 0x%lx paddr: 0x%x \n", alloc->count, alloc->vaddr, __pa(alloc->vaddr));


        spin_lock(&cma_lock);

        list_add_tail(&alloc->list, &cma_allocations);

        spin_unlock(&cma_lock);


        return count;

    } else {

        dev_err(cma_dev, "no mem in CMA area\n");

        kfree(alloc);

        return -ENOSPC;

    }

}



static const struct file_operations cma_test_fops = {

    .owner = THIS_MODULE,

    .read  = cma_test_read,

    .write = cma_test_write,

};


static struct miscdevice cma_test_misc = {

    .name = "cma_test",

    .fops = &cma_test_fops,

};


static int __init cma_test_init(void)

{

    struct device_node *np;

    struct cma *cma;

    int ret;


    ret = misc_register(&cma_test_misc);

    if(unlikely(ret)) {

        pr_err("failed to register cma test misc device!\n");

        goto err;

    }    


    cma_dev = cma_test_misc.this_device;

    dev_info(cma_dev, "registered.\n");


    np = of_find_node_by_path("/reserved-memory/video_cma@69000000");

    if (!np) {

        dev_info(cma_dev, "find node %s failed!\n", CMA_NAME);

        goto err;

    }

    dev_info(cma_dev, "find node %s ok!\n", CMA_NAME);


    cma = find_cma_by_name(CMA_NAME);

    if (cma) {

        dev_info(cma_dev, "find cma %s success, base pfn 0x%lx\n", cma->name,         cma->base_pfn);

        cma_dev->cma_area = cma;

    } else {

        dev_info(cma_dev, "find cma err!\n");

        goto err;

    }


    return 0;

err:

    return -EFAULT;

}


static void __exit cma_test_exit(void)

{

    misc_deregister(&cma_test_misc);

}


module_init(cma_test_init);

module_exit(cma_test_exit);

MODULE_LICENSE("GPL");

 

5 测试,基于内核5.0

注:旧的内核中cma结构体不含name成员,使用不是很方便。

首先对比内存信息

未添加video cma

cat /proc/meminfo

CmaTotal: 16384 kB

CmaFree: 14592 kB

 

free -m

                   total used free shared buffers cached

Mem:                497  18   478    0    0        1

-/+ buffers/cache:       17   480

 

添加video cma

cat /proc/meminfo

CmaTotal: 24576kB

CmaFree: 22784kB

 

free -m

                   total used free shared buffers cached

Mem:                497  18   478    0    0        1

-/+ buffers/cache:       17   480

 

 

对比得到,cmatotal和cmafree都增加了8M,符合添加8M预留区并加入cma系统的预期。

free看到total不变,说明预留区已放入伙伴系统。

 

使用这段CMA

echo 1024 > /dev/cma_test 
misc cma_test: alloc 1024 pages, vaddr: 0xc9000000 paddr: 0x69000000

cat /proc/meminfo 

CmaTotal: 24576 kB
CmaFree: 18688 kB

成功使用4M内存

 

释放这段内存

cat /dev/cma_test 
misc cma_test: free 1024 pages. vaddr: 0xc9000000 paddr: 0x69000000

cat /proc/meminfo 

CmaTotal: 24576 kB
CmaFree: 22244 kB

可以发现,内存并未完全释放。原因是产生了碎片,无法合并。

cam的碎片问题还是蛮严重的,建议一个需求一块cma。

 

总结一下:

在内存不断使用的过程中,会产生碎片,日益使用对内存消耗大的设备比如camera,video,将很难分配到足够大的内存。cma的技术提前分配一块专用内存,在不用的时候释放到伙伴系统中,在使用的时候通过页迁移腾出这块内存。

cma也是一种内存调节技术之一。

 

*部分内容参考网络

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux内存调节之CMA 的相关文章

  • 在内核代码中查找函数的最佳方法[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我开始浏览内核代码 遇到的一件事是如何跟踪函数调用 结构定义等 有没有一种好的方法可以快速跳转到函数定义并退出 我尝试过 Source N
  • 执行命令而不将其保留在历史记录中[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 在进行软件开发时 经常需要在命令行命令中包含机密信息 典型示例是将项目部署到服务器的凭据设置为环境变量 当我不想将某些命令存储在命令历史记
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • FileOutputStream.close() 中的设备 ioctl 不合适

    我有一些代码可以使用以下命令将一些首选项保存到文件中FileOutputStream 这是我已经写了一千遍的标准代码 FileOutputStream out new FileOutputStream file try BufferedOu
  • ALSA:snd_pcm_writei 调用时缓冲区不足

    当运行我最近从灰烬中带回来的旧程序时 我遇到了缓冲区不足的情况 该程序将原始声音文件完全加载到内存中 2100 字节长 525 帧 并准备 ALSA 进行输出 44 1khz 2 通道 有符号 16 位 if err snd pcm set
  • 为什么 Linux 没有 DirectX API?

    在考虑现代显卡的 Windows 系统上 DirectX API 的驱动程序端实现时 我想知道为什么此实现在非 Windows 系统 尤其是 Linux 上不可用 由于明显缺乏此功能 我只能假设有一个我无视的充分理由 但在我的原始理解中 我
  • 在 C 中使用单个消息队列是否可以实现双向通信

    我希望服务器向客户端发送一些消息 并让客户端确认它 我被分配了这个任务 我可以在 C linux 中使用单个消息队列来完成它还是我需要创建两个 谢谢 是的 可以使用 sysV 消息队列来做到这一点 从您之前的问题来看 您正在使用该队列 您可
  • python获取上传/下载速度

    我想在我的计算机上监控上传和下载速度 一个名为 conky 的程序已经在 conky conf 中执行了以下操作 Connection quality alignr wireless link qual perc wlan0 downspe
  • CMake 链接 glfw3 lib 错误

    我正在使用 CLion 并且正在使用 glfw3 库编写一个程序 http www glfw org docs latest http www glfw org docs latest 我安装并正确执行了库中的所有操作 我有 a 和 h 文
  • 如何让R使用所有处理器?

    我有一台运行 Windows XP 的四核笔记本电脑 但查看任务管理器 R 似乎一次只使用一个处理器 如何让 R 使用全部四个处理器并加速我的 R 程序 我有一个基本系统 我使用它在 for 循环上并行化我的程序 一旦您了解需要做什么 此方
  • 从 Xlib 转换为 xcb

    我目前正在将我的一个应用程序从 Xlib 移植到 libxcb 但在查找有关我有时使用的 XInput2 扩展的信息时遇到了一些麻烦 libxcb 中有 XInput2 实现吗 如果是的话 在哪里可以找到文档 目前我在使用此功能时遇到问题
  • 与 pthread 的进程间互斥

    我想使用一个互斥体 它将用于同步对两个不同进程共享的内存中驻留的某些变量的访问 我怎样才能做到这一点 执行该操作的代码示例将非常感激 以下示例演示了 Pthread 进程间互斥体的创建 使用和销毁 将示例推广到多个进程作为读者的练习 inc
  • Intel 上的 gcc 中的 _mm_pause 用法

    我参考过这个网页 https software intel com en us articles benefitting power and performance sleep loops https software intel com
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工
  • 错误:“rjags”的包或命名空间加载失败

    在终端的 conda 环境之一中 我能够成功安装包 rjags 但是 当我在该环境中运行 R 并运行库 rjags 时 出现以下错误 加载所需的包 coda 错误 rjags 的包或命名空间加载失败 rjags 的 loadNamespac
  • linux下如何从文本文件中获取值

    我有一些文本格式的文件 xxx conf 我在这个文件中有一些文本 disablelog 1 当我使用 grep r disablelog oscam conf 输出是 disablelog 1 但我只需要值1 请问你有什么想法吗 一种方法
  • 如何使用Android获取Linux内核的版本?

    如何在 Android 应用程序中获取 Linux 内核的版本 不是 100 确定 但我认为调用 uname r 需要 root 访问权限 无论如何 有一种不太肮脏的方法可以做到这一点 那就是 System getProperty os v
  • 检查已安装的软件包,如果没有找到则安装

    我需要检查已安装的软件包 如果未安装则安装它们 RHEL CentOS Fedora 示例 rpm qa grep glibc static glibc static 2 12 1 80 el6 3 5 i686 如何在 BASH 中进行检
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • 无法显示 Laravel 欢迎页面

    我的服务器位于 DigitalOcean 云上 我正在使用 Ubuntu 和 Apache Web 服务器 我的家用计算机运行的是 Windows 7 我使用 putty 作为终端 遵循所有指示https laracasts com ser

随机推荐

  • C语言中volatile关键字详解以及常见的面试问题

    编译器的优化 程序运行的优化可以分为硬件和软件 硬件上是在CPU和内存中间增加cache 来解决CPU和内存之间运行速率差异过大的问题 软件上则分为编译器优化和程序员优化 程序员优化是程序员在编写代码时 对代码的逻辑顺序进行合理安排 提升效
  • WIN10 修改用户下文件夹的名称

    转载note 我是为了解决正当防卫3不能存档 我的用户名当初设置的数字 转载的原因是 走了很多百度知道和经验的弯路 如果有人看到就别走了 我因为走了弯路前弄后弄导致原先的个人数据文件还丢失 只得跳出步骤新建用户 在PE下复制还有的数据 所以
  • 在windows系统安装linux

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 说明 二 步骤 1 利用WindowsADK安装windows 1 Windows 评估和部署工具包 ADK 包括 CopyPE 和 MakeWinPEM
  • no matching host key type found. Their offer: ssh-rsa 问题解决

    最近升级了Mac OS Ventura 13 0 1后发现ssh指定密钥登录服务器失败 no matching host key type found Their offer ssh rsa 进入当前用户的 ssh目录发现比之前系统多了一个
  • Ubuntu20.04安装qemu错误解决方法

    1 如果运行 configure显示没有找到pip sudo apt get install phthon3 pip 2 如果运行 configure显示 ninja error opening build log Permission d
  • com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver的区别

    com mysql jdbc Driver 是 mysql connector java 5中的 com mysql cj jdbc Driver 是 mysql connector java 6中的 1 JDBC连接Mysql5 com
  • [共同学习] 平衡二叉树浅见

    平衡二叉树 平衡二叉树的概念 AVL树结点的定义 AVL树的插入 左左 右单旋 右右 左单旋 左右 先左旋 再右旋 右左 先右旋 再左旋 AVL树的验证 验证其为二叉搜索树 验证其为平衡树 AVL树的性能 AVL树的实现 感悟 以上 二叉搜
  • 三分钟实现一个react-router-dom5.0的路由拦截(导航守卫)

    不同于vue 通过在路由里设置meta元字符实现路由拦截 在使用 Vue 框架提供了路由守卫功能 用来在进入某个路有前进行一些校验工作 如果校验失败 就跳转到 404 或者登陆页面 比如 Vue 中的 beforeEnter 函数 rout
  • element upload上传视频,获取本地url地址和时长

    获取视频的时长参考了文章 https www cnblogs com 65Seeker p 11466824 html 1 URL createObjectURL 静态方法会创建一个 DOMString 其中包含一个表示参数中给出的对象的U
  • SpringBoot项目中ModelMapper配置以及使用

    项目中对象与对象赋值转换使用的频率非常的高 比如数据库表实体对象 Entity 与业务类对象 Model 之间的赋值传递 或者模型对象 Model 与视图对象 ViewModel 之间的赋值传递 如果我们一个一个字段的赋值 将是非常繁琐并且
  • vue+element -UI前端Excel 文件导入数据

    完成的效果图如下 会进行数据筛选 根据你上传的物业名称跟数据库的名称对应 在这里我用到了一个插件 需要在在main js中全局引入 import export excel to json export json to excel from
  • linux之命名空间

    1 什么是命名空间 Linux中的命名空间 namespaces 是一种轻量级的虚拟化技术 ps docker就是依赖这个原理实现的 让进程看起来像是在自己的独立系统中运行 也就是说进程只能看到相同命名空间内的进程和资源 而看不到其他命名空
  • PG向表中添加新列时判断存在性

    以下是可以在命令行中执行的 SQL 语句 用于向表中添加新列并判断存在性 DO BEGIN BEGIN ALTER TABLE your table name ADD COLUMN IF NOT EXISTS your column nam
  • 服务器torchserver部署全流程踩坑记录

    服务器torchserver部署全流程踩坑记录 部署结果展示 一 Python环境 一 创建虚拟环境 二 安装torch cuda等 三 Python环境移植 二 java jdk环境 一 java jdk安装 1 sudo安装 需要sud
  • 使用selenium爬取唯品会

    使用selenium爬取唯品会 1 基本步骤 2 通过程序控制浏览器下拉滚动条获取加载信息 3 完成这个爬虫程序 使用selenium爬取动态加载的网页 爬取唯品会的商品 1 基本步骤 首先 创建一个浏览器驱动driver 查看唯品会页面u
  • 我的世界服务器聊天显示坐标,我的世界端游怎么显示坐标

    手机游戏cf的VIP等级会显示在最终游戏CF上吗 H 是的 无需感谢 我的世界如何环绕 单击显示不坐吗 前提是必须有一个区域插件 用木斧对角指向两个点 住所 牛仔竞技插件 您只能绘制自己的区域 其他 无法破坏或改变您的领土 每个玩家可以拥有
  • OpenCV机器视觉-识别红绿颜色

    识别红绿颜色 识别车道线 车道线检测 使用opencv来完成一个车道线检测的案例 完成这样的案例我们需要经历哪些步骤呢 我们先来思考一下解决问题的思路 当前情况下 摄像头拍出了很多的东西 例如路边的杂草远方的山 但是在我们自动驾驶的过程中
  • 【华为OD机试真题】补种未成活胡杨(C&C++&java&python&JavaScript&go)100%通过率【2023(B卷)100分】

    补种未成活胡杨 题目描述 近些年来 我国防沙治沙取得显著成果 某沙漠新种植 N 棵胡杨 编号 1 N 排成一排 一个月后 有 M 棵胡杨未能成活 现可补种胡杨 K 棵 请问如何补种 只能补种 不能新种 可以得到最多的连续胡杨树 输入描述 N
  • 【Android】Android ANR产生过程与分析方法

    前言 Android ANR问题一直是比较难解决的问题 一来它比较难以复现 二来复现后也不太好分析 这篇文章梳理一下ANR产生的过程以及出现ANR拿到日志文件如何定位原因 其实关于ANR线上监控也是比较棘手的 看了这篇文章我们再去看一些AN
  • linux内存调节之CMA

    本文贴代码过头了 以后想起来再优化一下吧 目录 概述 数据结构 构建初始化 DTS CONFIG DMA CMA 页表与物理页初始化 分配器激活 分配器使用 CMA部署 实战 概述 CMA Contiguous Memory Allocat