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 的相关文章

  • 如何真正释放 Linux 中的大页面以供新进程使用?

    真的找不到太多关于此的信息 希望有人可以提供帮助 我正在假脱机使用 100GB java 堆作为大数据缓存 为了避免与文件系统缓存等内容发生冲突 并且因为它通常性能更好 我将其分配在大页面中 我保留了 51 200 x 2MB 大页面 一切
  • 是否有我可以运行的操作系统命令来确定是否在基于 Xen 的虚拟机内运行

    我可以在基于 Xen 的虚拟机中运行一个操作系统命令来告诉我它是一个虚拟机而不是物理机 我听说内核对此有一些自我意识智能 例如就像 ps 输出中的额外列之类的 我知道 vmstat 提供了 st 列 但我在运行 Linux 内核 2 6 1
  • Snap-confine 具有提升的权限,并且不受限制,但应该受到限制。拒绝继续避免权限升级攻击

    我已经使用 snap 一段时间了 但最近升级后 当我尝试打开任何应用程序时 出现此错误 Snap confine has elevated permissions and is not confined but should be Refu
  • Nasm 打印到下一行

    我用 nasm Assembly 编写了以下程序 section text global start start Input variables mov edx inLen mov ecx inMsg mov ebx 1 mov eax 4
  • 使用 C++ 输出字符串覆盖 Linux 终端上的最后一个字符串

    假设我有一个命令行程序 有没有办法让我说的时候 std cout lt lt stuff 如果我不做std cout lt lt n 在另一个之间std cout lt lt stuff 东西的另一个输出将覆盖同一行上的最后一个东西 清理行
  • 如何使用libaudit?

    我试图了解如何使用 libaudit 我想接收有关使用 C C 的用户操作的事件 我不明白如何设置规则 以及如何获取有关用户操作的信息 例如 我想获取用户创建目录时的信息 int audit fd audit open struct aud
  • 变量作为 bash 数组索引?

    bin bash set x array counter 0 array value 1 array 0 0 0 for number in array do array array counter array value array co
  • Linux TCP服务器:在接受连接之前读取客户端的IP地址

    Related C Winsock API如何在接受连接之前获取连接客户端IP https stackoverflow com questions 716209 c winsock api how to get connecting cli
  • 原生 Linux 应用程序可像 ResHacker 一样编辑 Win32 PE

    我想运行自动修改 dll服务 用户提交特定的 dll 我在服务器上修改它 然后用户可以下载 dll的修改版本 是否有任何本机 Linux 应用程序提供常见的 Win32 PE 修改功能 例如图标 字符串 加速器 对话等 至少提供命令行或脚本
  • ARM 系统调用的接口是什么?它在 Linux 内核中的何处定义?

    我读过有关 Linux 中的系统调用的内容 并且到处都给出了有关 x86 架构的描述 0x80中断和SYSENTER 但我无法追踪 ARM 架构中系统调用的文件和进程 任何人都可以帮忙吗 我知道的几个相关文件是 arch arm kerne
  • 将 stdout 作为命令行 util 的文件名传递?

    我正在使用一个命令行实用程序 该实用程序需要传递文件名以将输出写入 例如 foo o output txt 它唯一写入的东西stdout是一条消息 表明它运行成功 我希望能够通过管道传输写入的所有内容output txt到另一个命令行实用程
  • sqlite 插入需要很长时间

    我正在将不到 200 000 行插入到 sqlite 数据库表中 我只是在终端中通过 sqlite3 使用一个非常简单的 sql 文件 我打赌它已经运行了至少 30 分钟 这是正常现象还是我应该关闭该过程并尝试不同的方法 sqlite中的插
  • Windows 与 Linux 文本文件读取

    问题是 我最近从 Windows 切换到 Ubuntu 我的一些用于分析数据文件的 python 脚本给了我错误 我不确定如何正确解决 我当前仪器的数据文件输出如下 Header 有关仪器等的各种信息 Data 状态 代码 温度 字段等 0
  • 是否有可能在linux中找到包含特定文本的文件?

    考虑这种情况 我在文件夹 Example 下有很多文件 如果我需要找到一个包含特定短语 如 Class Example 的文件 我该如何使用 Linux shell 来做到这一点 linux中有类似 定位 的函数可以做到这一点吗 Thank
  • R 未获取用户库

    我有一个带 R 3 6 0 的 Fedora 30 系统 用户库设置在Renviron就像这个 R LIBS USER R LIBS USER R x86 64 redhat linux gnu library 3 6 事实上 它出现在交互
  • 如何从 Linux 的 shell 中删除所有以 ._ 开头的文件?

    确实如标题所示 我已将许多文件从 Mac 复制到 Raspberry Pi 这导致了许多以前缀开头的多余文件 我想删除以以下开头的文件夹中的每个文件 我该怎么做 尝试类似的方法 cd path to directory rm rf 或者 如
  • Linux命令列出所有可用命令和别名

    是否有一个 Linux 命令可以列出该终端会话的所有可用命令和别名 就好像您输入 a 并按下 Tab 键一样 但针对的是字母表中的每个字母 或者运行 别名 但也返回命令 为什么 我想运行以下命令并查看命令是否可用 ListAllComman
  • 无关的库链接

    我有一个可能有点愚蠢的问题 因为我很确定我可能已经知道答案了 假设你有静态库A 动态共享库B和你的linux下的程序C 假设库 A 调用库 B 中的函数 并且您的程序调用库 A 中的函数 现在假设 C 在 A 中调用的所有函数都不使用 B
  • 进程名称长度的最大允许限制是多少?

    进程名称允许的最大长度是多少 我正在读取进程名称 proc pid stat文件 我想知道我需要的最大缓冲区 我很确定有一个可配置的限制 但就是找不到它在哪里 根据man 2 prctl http man7 org linux man pa
  • 如何通过代理将套接字连接到http服务器?

    最近 我使用 C 语言编写了一个程序 用于连接到本地运行的 HTTP 服务器 从而向该服务器发出请求 这对我来说效果很好 之后 我尝试使用相同的代码连接到网络上的另一台服务器 例如 www google com 但我无法连接并从网络中的代理

随机推荐

  • 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