版权声明:本文为本文为博主原创文章,转载请注明出处。如有错误,欢迎指正。

文章目录

    • 一、 xenomai内存池管理
      • 1.xnheap
      • 2. xnpagemap
      • 3. xnbucket
      • 4. xnheap初始化
      • 5. 内存块分配
        • 5.1 小内存分配流程(<= 2*PAGE_ZISE)
          • 1.分配1Byte
          • 2.分配50Byte
          • 3.分配1000 Byte
          • 4. 分配5000字节
        • 5.2 大内存分配(> 2*PAGE_ZISE)
          • 1. 分配10000字节
      • 6. 内存释放
        • 页内块释放
        • 页连续的块释放
      • 7. 总结

一、 xenomai内存池管理

通常,操作系统的内存管理,内存分配算法一定要快,否则会影响应用程序的运行效率,另一个是内存利用率,对该方面感兴趣的可查阅相关论文。

无论linux还是xenomai,在服务或管理应用程序过程中经常需要内存分配,通常linux内存的分配与释放都是时间不确定的,例如,缺页异常和页面换出会导致大且不可预测的延迟,不适用于受严格时间限制的实时应用程序。

xenomai作为硬实时内核,不能使用linux这样的内存分配释放接口,为此xenomai采取的措施是:在xenomai内核初始化时,先调用__vmalloc()从linux管理的ZONE_NORMAL中分配 一片内存,然后由xenomai自己来管理这片内存,且xenomai提供的内存分配释放时间确定的,这样就不会因为内存的分配释放影响实时性(该内存管理代码量非常少,有效代码数3百行左右,实现精巧,值得研究利用。在需要自己实现一个内存管理的场合很有帮助)。

下面代码基于 xenomai-3.0.8。xenomai 3.1开始有所不同详见文末。

1.xnheap

xenomai管理的内存池称为xnheap,内存池大小预先配置,如xenomai的系统内存池cobalt_heap,负责内核大多内核数据分配,其大小为sysheap_size_arg* 1024 Byte(sysheap_size_arg KB),sysheap_size_arg可在内核配置时设置,或者通过内核参数xenomai.sysheap_size=<kbytes>配置。xenomai内核中这样管理的内存池不止一个,其他的make menuconfig配置如下。

[*] Xenomai/cobalt  ---> Sizes and static limits  --->(512) Number of registry slots                                   (4096) Size of system heap (Kb) (512) Size of private heap (Kb) (512) Size of shared heap (Kb)   

简单介绍一下配置项中的几个内存池的用途:

  • (512) Number of registry slots,xenomai内核运行中内核资源对象存储槽的大小,用于分配系统使用资源的最大大小,如信号(signal)、互斥对象(mutex)、信号量等.
  • (4096) Size of system heap (Kb) 系统内存池,用于cobalt内核工作过程中动态内存分配,内核中很多任务共享的内存会从该区域分配,例如XDDP通讯时数据缓冲区默认从该区域分配。
  • (512) Size of private heap (Kb) 每个Cobalt任务私有的内存池,在实时任务创建时,从linux分配内存并初始化,位于Cobalt任务调度实体cobalt_process中,当实时任务内核上下文需要分配内存时,就会从该区域中获取,XDDP 通讯中可选从该内存区分配缓冲区。

本节以xenomai的系统内存池cobalt_heap为例来了解xenomai内存池管理。cobalt_heap在xenomai内核初始化过程中初始化,先调用__vmalloc()从linux管理的ZONE_NORMAL中分配,然后在调用xnheap_init()初始化。

static int __init xenomai_init(void)
{......ret = sys_init();......return ret;
}static __init int sys_init(void)
{void *heapaddr;int ret, cpu;heapaddr = xnheap_vmalloc(sysheap_size_arg * 1024);/*256 * 1024*/if (heapaddr == NULL ||xnheap_init(&cobalt_heap, heapaddr, sysheap_size_arg * 1024)) {/*初始heap*/return -ENOMEM;}xnheap_set_name(&cobalt_heap, "system heap");/*set heap name */....return 0;
}

xenomai要求管理的内存大小必须是PAGE_SIZE的倍数,且至少有2页,其最大值在xenomai3.0.8版本里为2GB(1<<31),其他版本可能有所改变。以sysheap_size_arg默认值256为例,即cobalt_heap大小256KB。

每个内存池分配一个对象xnheap来管理,xnheap结构如下。

struct xnpagemap {/** PFREE, PCONT, PLIST or log2 */u32 type : 8;/** Number of active blocks */u32 bcount : 24;
};
struct xnheap {/** SMP lock */DECLARE_XNLOCK(lock);/** Base address of the page array */caddr_t membase;/** Memory limit of page array */caddr_t memlim;/** Number of pages in the freelist */int npages;/** Head of the free page list  */caddr_t freelist;/** Address of the page map */struct xnpagemap *pagemap;/** Link to heapq */struct list_head next;/** log2 bucket list */struct xnbucket {caddr_t freelist;int fcount;} buckets[XNHEAP_NBUCKETS];char name[XNOBJECT_NAME_LEN];/** Size of storage area */u32 size;/** Used/busy storage size */u32 used;
};

其中,size标志该内存池的总大小,used标志已分配使用大小,npages表示该内存有多少页,membase管理的内存基地址,memlim记录内存结束地址.

2. xnpagemap

struct xnpagemap {/** PFREE, PCONT, PLIST or log2 */u32 type : 8;/** Number of active blocks */u32 bcount : 24;
};

pagemap管理着每一页,有多少页就需要多少项,pagemap.type表示该页面的类型,pagemap.bcount表示页面被分成这类大小的数量,小于1页分配才会将空闲页n分割成多块,才需要pagemap[n]来记录,pagemap通常管理着小于PAGE_SIZE的分配。pagemap.type有如下几类:

  • XNHEAP_PFREE(0) 表示该页面空闲

  • XNHEAP_PCONT(1)该页为上一页的续,当分配的内存大于1页时,除首页之外的页用该标识。

  • XNHEAP_PLIST(2) 表示该页是块的开始(每次请求分配的内存称为一个块)

  • 记录确切的子块大小(log2sizelog_2size),值为3-20,(页按size大小分割成许多子块);

3. xnbucket

	struct xnbucket {caddr_t freelist;int fcount;} buckets[XNHEAP_NBUCKETS];

buckets[XNHEAP_NBUCKETS]记录着整个xnheap不同大小的分配,因为bucket管理的内存分配单元大小最小为8Byte,所以数组下标是log2size3log_2size -3,bucket[n]管理着分配单元(块)大小为2n+32^{n+3}Byte的内存池,freelist指向该bucket内第一个空闲块,fcount标识该bucket可剩余空闲块数。

例如请求分配的大小为64Byte,log2643=3log_264 -3 = 3,则buckets[3]记录着请求大小64Byte的分配,如果buckets[3].freelist不为NULL,则buckets[3].freelist就是本次请求的内存首地址。

并不是任何大小的分配都由buckets[]管理。当请求大小超过两个页时,不再使用bucket,从空闲页列表直接分配页面会更节省空间。XNHEAP_NBUCKETS=21,表示最大管理8MB(220+32^{20+3})分配信息,普通分页模式下,页大小为4KB,只用到buckets[0-10],大页(hupage)模式(页大小为2MB)下才会使用到buckets[11-20]以下分析默认页大小为4KB

buckets与pagemap区别是管理的对象不同,buckets[n]管理大小2n+32^{n+3}Byte的内存池的分配。而pagemap[n]记录整个块内存第n页内的使用信息。

4. xnheap初始化

当分配到一片内存作为xnheap后,首先调用xnheap_init()对该片内存初始化。

int xnheap_init(struct xnheap *heap, void *membase, u32 size)
{spl_t s;secondary_mode_only();heap->size = size;heap->membase = membase;heap->npages = size / XNHEAP_PAGESZ; if (heap->npages < 2) return -EINVAL;heap->pagemap = kmalloc(sizeof(struct xnpagemap) * heap->npages,GFP_KERNEL);/*map 大小:每页需要一个struct xnpagemap*/if (heap->pagemap == NULL)return -ENOMEM;xnlock_init(&heap->lock);init_freelist(heap);/* Default name, override with xnheap_set_name() */ksformat(heap->name, sizeof(heap->name), "(%p)", heap);.....return 0;
}

计算该内存总页数npages,然后为每页分配一个xnpagemap对象,npages页需要分配npages个xnpagemap,然后调用init_freelist()初始化freelist。

static void init_freelist(struct xnheap *heap)
{caddr_t freepage;int n, lastpgnum;heap->used = 0;memset(heap->buckets, 0, sizeof(heap->buckets));lastpgnum = heap->npages - 1;for (n = 0, freepage = heap->membase;n < lastpgnum; n++, freepage += XNHEAP_PAGESZ) {*((caddr_t *)freepage) = freepage + XNHEAP_PAGESZ;heap->pagemap[n].type = XNHEAP_PFREE;heap->pagemap[n].bcount = 0;}*((caddr_t *) freepage) = NULL; heap->pagemap[lastpgnum].type = XNHEAP_PFREE;heap->pagemap[lastpgnum].bcount = 0;heap->memlim = freepage + XNHEAP_PAGESZ;/* The first page starts the free list. */heap->freelist = heap->membase;/*free list*/
}

先初始化pagemap[],每页记录为未使用(XNHEAP_PFREE)

设置xnheap的结束地址memlim,并将freelist指向第一个空闲页,然后从第一页开始,前一页保存着后一页起始地址。这样做不仅将空闲页连起来,方便分配时索引,而且**通过内存赋值操作,如果该内存页未映射,会触发内核缺页异常,让linux将未映射到物理内存的页面映射到物理内存,这样后续xenomai使用过程中就不会再产生缺页中断,避免影响xenomai实时性。**初始化后如下图所示

5. 内存块分配

xenomai内存堆初始化完后,下面通过分配与释放来分析分配释放过程,例如向内存池Cobalt_heap()分别分配1Byte、50Byte、1000Byte、5000Byte、10000Byte数据,然后依次释放。

/*向hobalt_heap分配1字节空间*/
ptrt_1 = xnheap_alloc(&hobalt_heap, 1);
/*向hobalt_heap分配50字节空间*/
ptr_50 = xnheap_alloc(&hobalt_heap, 50);
/*连续向hobalt_heap分配1000字节空间5次*/
ptr_1000 = xnheap_alloc(&hobalt_heap, 1000);
ptr_1000_1 = xnheap_alloc(&hobalt_heap, 1000);
ptr_1000_2 = xnheap_alloc(&hobalt_heap, 1000);
ptr_1000_3 = xnheap_alloc(&hobalt_heap, 1000);
ptr_1000_4 = xnheap_alloc(&hobalt_heap, 1000);
/*向hobalt_heap分配5000字节空间*/
ptr_5000 = xnheap_alloc(&hobalt_heap, 5000);
/*向hobalt_heap分配10000字节空间*/
ptr_10000 = xnheap_alloc(&hobalt_heap, 10000);

5.1 小内存分配流程(<= 2*PAGE_ZISE)

1.分配1Byte

首先来看分配1Byte。

/*include\cobalt\kernel\heap.h*/
#define XNHEAP_PAGESZ	  PAGE_SIZE
#define XNHEAP_MINLOG2    3
#define XNHEAP_MAXLOG2    22	/* Holds pagemap.bcount blocks */
#define XNHEAP_MINALLOCSZ (1 << XNHEAP_MINLOG2)
#define XNHEAP_MINALIGNSZ (1 << 4) /* i.e. 16 bytes */
#define XNHEAP_NBUCKETS   (XNHEAP_MAXLOG2 - XNHEAP_MINLOG2 + 2)
#define XNHEAP_MAXHEAPSZ  (1 << 31) /* i.e. 2Gb */void *xnheap_alloc(struct xnheap *heap, u32 size)
{u32 pagenum, bsize;int log2size, ilog;caddr_t block;spl_t s;
...../** Sizes lower or equal to the page size are rounded either to* the minimum allocation size if lower than this value, or to* the minimum alignment size if greater or equal to this* value.*/if (size > XNHEAP_PAGESZ)size = ALIGN(size, XNHEAP_PAGESZ);/*XNHEAP_PAGESZ = */else if (size <= XNHEAP_MINALIGNSZ)size = ALIGN(size, XNHEAP_MINALLOCSZ);elsesize = ALIGN(size, XNHEAP_MINALIGNSZ);......
}

首先根据大小size来向最小分配或最大分配对齐,xenomai分配类型分为3类,对于大于XNHEAP_PAGESZ的向上与XNHEAP_PAGESZ对齐;对于小于8Byte的,向上与8Byte对齐;对于大于8Byte,向上与16Byte对齐;这样是为了与bucket一一对应。

例如分配5000Byte,最终分配到的空间大小为8192 Byte(以PAGE_SIZE为4KB计算),要分配1Byte空间,将会得到8Byte的空间,分配50Byte空间得到64Byte空间。

我们请求分配1Byte的内存,对齐后size为8 Byte,buckets[XNHEAP_NBUCKETS]只管理请求大小小于2*PAGE_SZIE的分配池。 当请求的大小大于页大小的2倍时,从空闲页列表直接分配页面会更节省空间。8Byte小于2*PAGE_SZIE,下面看bucket具体的分配流程。

	if (likely(size <= XNHEAP_PAGESZ * 2)) {   /*小于等于2PAGE_SIZE的从空闲链表中分配*//** Find the first power of two greater or equal to the* rounded size.*/bsize = size < XNHEAP_MINALLOCSZ ? XNHEAP_MINALLOCSZ : size;log2size = order_base_2(bsize);bsize = 1 << log2size;ilog = log2size - XNHEAP_MINLOG2; xnlock_get_irqsave(&heap->lock, s);block = heap->buckets[ilog].freelist;if (block == NULL) {block = get_free_range(heap, bsize, log2size);if (block == NULL)goto out;if (bsize <= XNHEAP_PAGESZ)heap->buckets[ilog].fcount += (XNHEAP_PAGESZ >> log2size) - 1;} else {if (bsize <= XNHEAP_PAGESZ)	--heap->buckets[ilog].fcount;pagenum = ((caddr_t)block - heap->membase) / XNHEAP_PAGESZ;++heap->pagemap[pagenum].bcount;}heap->buckets[ilog].freelist = *((caddr_t *)block);heap->used += bsize;} else {.....}

第一步先对size求log2sizelog_2sizelog28log_28=3,得到bucket索引下标ilog=log283=0ilog = log_28-3=0,再用ilog作为下标得到管理8Byte大小池的bucket,buckets[0].freelist指向首个空闲块,如果buckets[ilog].freelist不为NULL,则将buckets[ilog].freelist指向的块分配出去,buckets[ilog].fcount减一,再根据freelist的地址计算该空闲块位于第几页(pagenum),更新该页的pagemap[pagenum].bcount。再将buckets[ilog].freelist指向下一个空闲页,更新总内存已分配大小heap->used,返回分配到的内存地址block。

但我们内存池刚初始化,buckets[ilog].freelist 为NULL,进入block==NULL分支,先为该bucket分配空间。

先通过get_free_range()分配,分配后计算bucket的剩余块数buckets[ilog].fcount,XNHEAP_PAGESZ >> log2size就是新页面被分成了多少块,且马上就要被分配出去耍一块,所以再减一。

下面看如何分配bucket管理的空间,get_free_range()中,先分配空闲页,然后再对空闲页进行分块。先看从整块内存找空闲页部分

static caddr_t get_free_range(struct xnheap *heap, u32 bsize, int log2size)
{caddr_t block, eblock, freepage, lastpage, headpage, freehead = NULL;u32 pagenum, pagecont, freecont;freepage = heap->freelist;		/*空闲页*/while (freepage) {headpage = freepage;freecont = 0;do {lastpage = freepage;freepage = *((caddr_t *) freepage);freecont += XNHEAP_PAGESZ;}while (freepage == lastpage + XNHEAP_PAGESZ && freecont < bsize);if (freecont >= bsize) {if (headpage == heap->freelist)heap->freelist = *((caddr_t *)lastpage);else*((caddr_t *)freehead) = *((caddr_t *)lastpage);goto splitpage;}freehead = lastpage;}return NULL;splitpage:......return headpage;
}

heap->freelist指向xnheap内存中第一个空闲页,10-14行循环迭代freepage并记录大小freecont,直到得到freecont大小的空闲页。我们传入get_free_range()的bsize=8,log2sizelog_2size = 3,所以循环1次,分配到4KB空间就够了。如下图所示.

条件freecont >= bsize表示分配到了满足大小的连续空闲页,否则就是连续内存空间不够,看lastpage指向的下一个空闲空间是否连续,直到分配到符合条件的内存页,否则无法满足此次分配条件,返回 NULL。

我们这里分配到了页0,20行更新heap->freelist指向下一个空闲页 。

跳转splitpage对页0进行切割。

splitpage:if (bsize < XNHEAP_PAGESZ) {	for (block = headpage, eblock =headpage + XNHEAP_PAGESZ - bsize; block < eblock;block += bsize)*((caddr_t *)block) = block + bsize;*((caddr_t *)eblock) = NULL;} else*((caddr_t *)headpage) = NULL;pagenum = (headpage - heap->membase) / XNHEAP_PAGESZ;heap->pagemap[pagenum].type = log2size ? : XNHEAP_PLIST;	heap->pagemap[pagenum].bcount = 1;for (pagecont = bsize / XNHEAP_PAGESZ; pagecont > 1; pagecont--) {heap->pagemap[pagenum + pagecont - 1].type = XNHEAP_PCONT;heap->pagemap[pagenum + pagecont - 1].bcount = 0;}return headpage;

splitpage操作将一个4K大小的页分成一个个大小为8Byte的块,并将这些块连起来,并更xpagemap[pagenum]的type为块大小3(2的幂log2blocksizelog_2blocksize),表示该页PLIST。bcount=1是即将分配出去的第一个块。

回到xnheap_alloc(),更新bucket内剩余块数heap->buckets[3].fcount、8字节池空闲地址buckets[3].freelist,整个内存池已分配数heap->used,然后返回内存池分配的到的内存起始地址ptr_1。此时如下:

通过以上分析,我们分配1字节空间,最终得到8字节的空间,8(1<<3)字节是xenomai内存池的最小管理单位,并且下次再分配8Byte内空间时,直接返回buckets[3].freelist并更新几个成员变量即可,速度极快。

2.分配50Byte

同样,根据以上步骤请求分配50字节空间时,先对50向上向上对齐得到64,计算bucket索引ilog=log2643=3ilog = log_2 64-3=3,本次分配请求从bucket[3]管理的内存池中分配,由于首次分配,bucket[3]中没有还管理的空间需要先从xnheap中分配空闲页,最终分配得到64字节大小的空间,分配后如下图所示。

3.分配1000 Byte

请求分配1000字节空间时,先对1000向上对齐得到1024,计算bucket索引ilog=log210243=7ilog = log_2 1024-3=7,本次分配请求从bucket[7]管理的内存池中分配,由于首次分配,bucket[7]中没有还管理的空间需要先从xnheap中分配一个空闲页分成4块交给bucket管理,最终本次分配得到1024字节大小的空间,分配后如下图所示。

以上分配后,buckets[7]中还剩余3个空闲块,如果bucket内的所有块分配完了,再次请求分配大小为1000字节的空间时会怎样?会再去分配一页空闲页进行切割。为了表示这个过程,继续执行以下语句,当ptr_1000_4分配后如下图所示。

ptr_1000_1 = xnheap_alloc(&hobalt_heap, 1000);
ptr_1000_2 = xnheap_alloc(&hobalt_heap, 1000);
ptr_1000_3 = xnheap_alloc(&hobalt_heap, 1000);
ptr_1000_4 = xnheap_alloc(&hobalt_heap, 1000);

当分配ptr_1000_3后bucket中不再由空闲块,bucket[7].freelist重新指向NULL,分配ptr_1000_4时就会触发再次从总内存分配空闲页来分成1K大小的块,分配ptr_1000_4后bucket[7].freelist指向新的空闲页。

4. 分配5000字节

由于请求大小是5000字节,前面说过超过页大小后会与页对齐,也就是8K的空间,且该大小满足<=2*PAGE_SIZE,会向bucket[13]分配。

与小于页大小(4KB)的分配不同的是,向页对齐后8K,8K空间占用2个页,所以图中连续的页5、页5分配出去,bucket内没有剩余块,页5对应的xnpagemap[5]的type被设置为XNHEAP_PCONT(1)表示该页与上页是连续的。

5.2 大内存分配(> 2*PAGE_ZISE)

1. 分配10000字节

由于请求大小是10000字节,前面说过超过页大小后会与页对齐,也就是12K的空间,对于大于8K(2*PAGE)SIZE)大小的分配请求,从空闲页列表直接分配页面会更节省空间。

	if (likely(size <= XNHEAP_PAGESZ * 2)) { /*小于8KB*/......} else {if (size > heap->size)return NULL;xnlock_get_irqsave(&heap->lock, s);/* Directly request a free page range. */block = get_free_range(heap, size, 0);if (block)heap->used += size;}

先判断总大小,然后调用get_free_range()直接从空闲页列表直接分配,参数log2sizelog_2size=0,该情况下get_free_range()函数执行路径如下;

static caddr_t get_free_range(struct xnheap *heap, u32 bsize, int log2size)
{caddr_t block, eblock, freepage, lastpage, headpage, freehead = NULL;u32 pagenum, pagecont, freecont;freepage = heap->freelist;while (freepage) {headpage = freepage;freecont = 0;/*在空闲页列表查找满足条件的连续空闲页*/do {lastpage = freepage;freepage = *((caddr_t *) freepage);freecont += XNHEAP_PAGESZ;}while (freepage == lastpage + XNHEAP_PAGESZ &&freecont < bsize);if (freecont >= bsize) {	/*得到连续的页*/if (headpage == heap->freelist)heap->freelist = *((caddr_t *)lastpage);	/*更新freelist*/else.....goto splitpage;}freehead = lastpage;}return NULL;splitpage:if (bsize < XNHEAP_PAGESZ) {	//<4K.....} else*((caddr_t *)headpage) = NULL;pagenum = (headpage - heap->membase) / XNHEAP_PAGESZ;heap->pagemap[pagenum].type = log2size ? : XNHEAP_PLIST;	heap->pagemap[pagenum].bcount = 1;for (pagecont = bsize / XNHEAP_PAGESZ; pagecont > 1; pagecont--) {heap->pagemap[pagenum + pagecont - 1].type = XNHEAP_PCONT;heap->pagemap[pagenum + pagecont - 1].bcount = 0;}return headpage;
}

分配后的内存视图如下。

6. 内存释放

通过以上分析,我们可以将分配到的内存块分为两类:

  • 从bucket中分配,大小小于等于4KB,不仅bucket记录着数量,该块所在页的pagemap[].type也记录着该块的大小。
  • 直接从空闲列表分配,大小大于4KB,pagemap[n].type为XNHEAP_PLIST(2)表示页n是该块的开始页,后续的n+i页,pagemap[n+i].type都为XNHEAP_PCONT(1)。

内存块释放的过程就是根据这些信息来定位要释放的块,并将它重新放回bucket内存池或空闲页列表。

通过xnheap_alloc()分配的内存,通过xnheap_free()释放,当然必须是在同一个xnheap上操作。

void xnheap_free(struct xnheap *heap, void *block)
{caddr_t freepage, lastpage, nextpage, tailpage, freeptr, *tailptr;int log2size, npages, nblocks, xpage, ilog;u32 pagenum, pagecont, boffset, bsize;spl_t s;xnlock_get_irqsave(&heap->lock, s);if ((caddr_t)block < heap->membase || (caddr_t)block >= heap->memlim)goto bad_block;/* Compute the heading page number in the page map. */pagenum = ((caddr_t)block - heap->membase) / XNHEAP_PAGESZ;boffset = ((caddr_t)block - (heap->membase + pagenum * XNHEAP_PAGESZ));switch (heap->pagemap[pagenum].type) {case XNHEAP_PFREE:	/* Unallocated page? */case XNHEAP_PCONT:	/* Not a range heading page? */
bad_block:xnlock_put_irqrestore(&heap->lock, s);XENO_BUG(COBALT);return;case XNHEAP_PLIST:		/**/.....break;default:.......}heap->used -= bsize;xnlock_put_irqrestore(&heap->lock, s);
}

xnheap_free()中先根据地址判断释放的内存块是否属于指定的xnheap。如果合法的,接着计算要释放的内存所在的页号pagenum,以及页内的偏移量boffset。得到页号后从pagemap[pagenum]判断要释放的内存块属于那种类型,再做相应的释放操作。

将前面分配到的内存按不同顺序释放,来查看xnheap的释放流程,由于分配的1000字节的几个内存块比较具有代表性,先看他们的释放,释放顺序如下。

/*释放*/
xnheap_free(&hobalt_heap, ptr_1000_1);
xnheap_free(&hobalt_heap, ptr_1000);
xnheap_free(&hobalt_heap, ptr_1000_3);
xnheap_free(&hobalt_heap, ptr_1000_2);
xnheap_free(&hobalt_heap, ptr_1000_4);

页内块释放

首先释放ptr_1000_1,ptr_1000_1实际指向的内存块可用空间为1024字节,首先计算ptr_1000_1所在的内存页页号pagenum = 2,以及页内的偏移量boffset = 1024.根据页号得到该页的类型pagemap[2].type=10,表示该已分配给buckets管理,跳转执行具体释放操作:

    switch (heap->pagemap[pagenum].type) {case XNHEAP_PFREE:	/* Unallocated page? */case XNHEAP_PCONT:	/* Not a range heading page? */bad_block:xnlock_put_irqrestore(&heap->lock, s);XENO_BUG(COBALT);return;case XNHEAP_PLIST:		.....break;default:log2size = heap->pagemap[pagenum].type;bsize = (1 << log2size);if ((boffset & (bsize - 1)) != 0) /* Not a block start? */goto bad_block;ilog = log2size - XNHEAP_MINLOG2;if (likely(--heap->pagemap[pagenum].bcount > 0)) {/* Return the block to the bucketed memory space. */*((caddr_t *)block) = heap->buckets[ilog].freelist;heap->buckets[ilog].freelist = block;++heap->buckets[ilog].fcount;break;}.....}heap->used -= bsize;

从pagemap[2].type得到log2size = 10,反算出我们释放的指针指向的内存块大小bsize = 1024字节。知道要释放的内存大小后,验证该地址是否是合法的内存块起始地址,验证方法就是看该地址是否与bsize对齐 。

验证合法后开始释放,要释放的内存属于bucket管理,计算buckets[]下标ilog=103=7ilog =10-3=7,属于buckets[7]管理。先将页信息pagemap[pagenum].bcount减一,判断是不是页内要释放的最后一个内存块,如果是另行处理。22-24行将该该块内存放回bucket[7],将释放的内存指向原来的freelist,freelist指向释放的块,更新fcount值,完成ptr_1000_1的释放。更新整个xnheap内存使用量。释放ptr_1000_1后的内存视图如下。

接着依次释放ptr_1000、ptr_1000_3与释放ptr_1000_1一致,释放后如图所示

此时pagemap[3].bcount=1,当释放最后一个内存块 ptr_1000_2时,由于是该页最后一块情况有所不同,条件(–heap->pagemap[pagenum].bcount > 0)不满足。执行如下.

	default:log2size = heap->pagemap[pagenum].type;/*10*/bsize = (1 << log2size);/*1024*/if ((boffset & (bsize - 1)) != 0) /* Not a block start? */goto bad_block;ilog = log2size - XNHEAP_MINLOG2;if (likely(--heap->pagemap[pagenum].bcount > 0)) {......break;}npages = bsize / XNHEAP_PAGESZ; if (unlikely(npages > 1))goto free_page_list;freepage = heap->membase + pagenum * XNHEAP_PAGESZ;block = freepage;tailpage = freepage;nextpage = freepage + XNHEAP_PAGESZ;nblocks = XNHEAP_PAGESZ >> log2size;heap->buckets[ilog].fcount -= (nblocks - 1);XENO_BUG_ON(COBALT, heap->buckets[ilog].fcount < 0);if (likely(heap->buckets[ilog].fcount == 0)) {heap->buckets[ilog].freelist = NULL;goto free_pages;}/** Worst case: multiple pages are traversed by the* bucket list. Scan the list to remove all blocks* belonging to the freed page. We are done whenever* all possible blocks from the freed page have been* traversed, or we hit the end of list, whichever* comes first.*/for (tailptr = &heap->buckets[ilog].freelist, freeptr = *tailptr, xpage = 1;freeptr != NULL && nblocks > 0; freeptr = *((caddr_t *) freeptr)) {if (unlikely(freeptr < freepage || freeptr >= nextpage)) {if (unlikely(xpage)) {*tailptr = freeptr;xpage = 0;}tailptr = (caddr_t *)freeptr;} else {--nblocks;xpage = 1;}}*tailptr = freeptr;goto free_pages;}heap->used -= bsize;

现在知道了该块是页的最后一块,接着看该块否是bucket[7]中的最后一个块,判断方式为看fcount-nblocks - 1是否等于0,如下。

nblocks = XNHEAP_PAGESZ >> log2size;
heap->buckets[ilog].fcount -= (nblocks - 1);
if (likely(heap->buckets[ilog].fcount == 0)) { /*是*/heap->buckets[ilog].freelist = NULL;goto free_pages;
}

不是bucket的最后一块,但是页2已经全部空闲,接下来重整页面。

	for (tailptr = &heap->buckets[ilog].freelist, freeptr = *tailptr, xpage = 1;freeptr != NULL && nblocks > 0; freeptr = *((caddr_t *) freeptr)) {if (unlikely(freeptr < freepage || freeptr >= nextpage)) {if (unlikely(xpage)) {*tailptr = freeptr;xpage = 0;}tailptr = (caddr_t *)freeptr;} else {--nblocks;xpage = 1;}}*tailptr = freeptr;goto free_pages;

根据frelist找出已经空闲的页,然后跳转至标签free_pages进行释放页2,free_pages主要调整空闲页之间的freelist,是链表freelist保持递增。

	free_pages:/* Mark the released pages as free. */for (pagecont = 0; pagecont < npages; pagecont++)heap->pagemap[pagenum + pagecont].type = XNHEAP_PFREE;/** Return the sub-list to the free page list, keeping* an increasing address order to favor coalescence.*/for (nextpage = heap->freelist, lastpage = NULL;nextpage != NULL && nextpage < (caddr_t) block;lastpage = nextpage, nextpage = *((caddr_t *)nextpage));	/* Loop */*((caddr_t *)tailpage) = nextpage;if (lastpage)*((caddr_t *)lastpage) = (caddr_t)block;elseheap->freelist = (caddr_t)block;break;

下面释放ptr_1000_4,由于ptr_1000_4是bucket[7]最后一块直接将bucket[7].freelist指向NULL,然后跳转至标签free_pages进行释放页3就行,释放后如下。

ptrt_1、ptr_50、ptr_5000均为页和bucket的最后一块,释放流程相同,不再说明。

页连续的块释放

最后看一下ptr_10000的释放,ptr_10000占用连续的3个页,同样根据ptr_10000计算出块开始页的tpye=2(XNHEAP_PLIST),进入XNHEAP_PLIST分支释放,通过看紧接着的页的tpye计算内存块的页数npages。计算该内存块的大小bsize,接着开始释放页。

void xnheap_free(struct xnheap *heap, void *block)
{caddr_t freepage, lastpage, nextpage, tailpage, freeptr, *tailptr;int log2size, npages, nblocks, xpage, ilog;u32 pagenum, pagecont, boffset, bsize;spl_t s;
......./* Compute the heading page number in the page map. */pagenum = ((caddr_t)block - heap->membase) / XNHEAP_PAGESZ;boffset = ((caddr_t)block - (heap->membase + pagenum * XNHEAP_PAGESZ));switch (heap->pagemap[pagenum].type) {case XNHEAP_PFREE:	/* Unallocated page? */case XNHEAP_PCONT:	/* Not a range heading page? */bad_block:xnlock_put_irqrestore(&heap->lock, s);XENO_BUG(COBALT);return;case XNHEAP_PLIST:npages = 1;while (npages < heap->npages &&heap->pagemap[pagenum + npages].type == XNHEAP_PCONT)npages++;bsize = npages * XNHEAP_PAGESZ;free_page_list:/* Link all freed pages in a single sub-list. */for (freepage = (caddr_t) block,tailpage = (caddr_t) block + bsize - XNHEAP_PAGESZ;freepage < tailpage; freepage += XNHEAP_PAGESZ)*((caddr_t *) freepage) = freepage + XNHEAP_PAGESZ;.......default:......}heap->used -= bsize;

freepage指向块的第一页,tailpage指向块的最后一页,将释放的几页链起来,成为一个子列表,如图所示。

现在仅将块内的页链接起来,接下来执行标签free_pages,将这些要释放的页链接到空闲页列表。

先将这些也对应的pagemap.type标志为空闲(XNHEAP_FREE)。

free_pages:/* Mark the released pages as free. */for (pagecont = 0; pagecont < npages; pagecont++)heap->pagemap[pagenum + pagecont].type = XNHEAP_PFREE;

将子列表放回空闲页列表,并保持它们递增的链接关系。

		for (nextpage = heap->freelist, lastpage = NULL;nextpage != NULL && nextpage < (caddr_t) block;lastpage = nextpage, nextpage = *((caddr_t *)nextpage));	/* Loop */*((caddr_t *)tailpage) = nextpage;if (lastpage)*((caddr_t *)lastpage) = (caddr_t)block;elseheap->freelist = (caddr_t)block;break;

将子列表插入空闲链表后,完成释放,视图如下(ptrt_1、ptr_50、ptr_5000还未释放)。

7. 总结

xenomai内核通过自己管理一片内存来避免内存分配释放影响实时性。

针对小于2*PAGE_SIZE 的内存请求,xnheap使用bucket建立内存池,使小内存请求迅速得到满足。对于大于2*PAGE_SIZE 的内存请求,直接向空闲页列表分配。

缺点:当内存页列表比较疏松时,可能会出现分配一个大内存(>4K)需要遍历所有空闲页到最后才分配到的情况。此时复杂度为O(n)O(n),n表示空闲页块数。xenomai3.1对此进行了优化,使用红黑树按空闲块大小来管理空闲页,通过大小直接查找空闲页速度极快,红黑树时间复杂度O(logn)O(logn),此外从红黑树中分配的内存从原来4K改变为512Byte对齐,这样使内存利用率进一步提高,有机会继续出一篇关于xenomai 3.1内存管理的文章。

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

相关文章

  1. 服务熔断与降级(Hystrix)

    目录服务熔断服务降级熔断VS降级Hystrix简介​使用Hystrix引入Hystrix依赖Feign结合Hystrix修改Feign客户端监控Hystrix 启用健康监控启用Hystrix-Dashboard引入Hystrix-Dashboard依赖这个也可以服务熔断服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的…...

    2024/5/10 11:09:30
  2. [源码] java8 ArrayList解析

    首先看ArrayList实现了 List ,RandomAccess , Cloneable , java.io.Serializable 其中的RandomAccess 代表其拥有随机快速访问的能力 因为其底层数据结构是数组,是占据一块连续的内存空间,所以其空间效率不高,但是可以根据下标读写(改查)元素,时间效率很高,当集合中的元…...

    2024/4/17 7:26:18
  3. 机器学习系列21-无监督学习之近邻嵌入

    Unsupervised Learning: Neighbor Embedding 如果本文对你有帮助,请给我的github打个star叭,上面附有全系列目录和内容! 更多优质内容欢迎关注我的微信公众号“Sakura的知识库”:本文介绍了非线性降维的一些算法,包括局部线性嵌入LLE、拉普拉斯特征映射和t分布随机邻居嵌入…...

    2024/4/18 16:24:49
  4. 机器学习时代三大神器GBDT、XGBoost、LightGBM

    机器学习时代三大神器GBDT、XGBoost、LightGBMGBDT梯度提升决策树Boosting方法是一种用来提高弱分类算法准确度的方法,Boosting算法的思想是将许多弱分类器集成在一起形成一个强分类器...

    2024/4/14 13:11:36
  5. 编写可测试的JavaScript代码

    什么是可测试的代码 编写可测试代码的关键在于让代码保持短小、整洁、简单和松耦合。 代码复杂度 基于事件的架构 3.1 基于事件编程的好处 代码单元测试 代码覆盖率 代码覆盖率通常与单元测试有关。代码覆盖率是单元测试的一个很好的衡量标准 集成测试 性能测试 负载测试 调试和…...

    2024/5/10 6:16:40
  6. C/C++ 中break用法

    break语句作用:用于跳出选择结构或者循环结构break使用的时机:1、出现在switch条件语句中,作用是终止case并跳出switch。2、出现在循环语句(for/while/do-while)中,作用是跳出当前的循环语句。3、出现在嵌套循环中,跳出内层循环语句。示例:1、switch中使用#include <…...

    2024/4/14 17:56:04
  7. 第三步用户注册,用户登陆

    1、导入静态文件,并把支持页面复制到模板template下,导入静态资源设置2、注册页面视图校验,激活校验,发送邮件激活,发邮件有可能时间等的太久,用celery来解决** celery启用 **from django.conf import settings from celery import Celery from django.core.mail import …...

    2024/4/14 15:17:09
  8. 【博客339】简述:微服务的故障及处理

    内容: 记录微服务的故障及处理方法 微服务故障类型: 1、集群故障。微服务系统一般都是集群部署的,根据业务量大小而定,集群规模从几台到甚至上万台 都有可能。一旦某些代码出现 bug,可能整个集群都会发生故障,不能提供对外提供服务。2、单IDC故障。现在大多数互联网公司为…...

    2024/4/24 7:32:06
  9. Java内存泄漏分析和解决

    最近正在熟悉Java内存泄漏的相关知识,上网查阅了一些资料,在此做个整理算是对收获的一些总结,希望能对各位有所帮助,有问题可以文末留言探讨、补充。如下是整篇文章的结构,所需阅读时间大约20minJava当中的内存泄漏1. 什么是内存泄漏?内存泄漏:对象已经没有被应用程序使…...

    2024/5/8 10:16:48
  10. 解决java.sql.SQLException: Access denied for user ‘root‘@‘localhost‘ (using password: YES)

    今天在学spring boot时,出现“拒绝访问数据库”的问题,原因是权限不够 解决方法: (因为本人是用宝塔创建的数据库,所有以宝塔为例) 1.打开宝塔服务,找到自己的数据库管理找到root密码之后,打开数据库连接工具,用户名默认是root,密码就是上面这一串。 2.打开数据库之后…...

    2024/5/10 7:39:45
  11. 装饰器模式

    在不改变原有对象的基础上,将功能附加到对象上基本功能的接口:/*** 定义一个接口* Create by yang_zzu on 2020/7/12 on 20:21*/ public interface Component {void iperation(); }抽象类,继承该接口:/*** 因为是抽象类需使用 implements 可以不实现接口* 用于被其他类继承…...

    2024/4/14 13:12:36
  12. (精华)2020年7月12日 vue 手搭脚手架vue-cli

    Vue.js 一、 单文件组件 1. .vue文件 .vue文件,称为单文件组件,是Vue.js自定义的一种文件格式,一个.vue文件就是一个单独的组件,在文件内封装了组件相关的代码:html、css、js.vue文件由三部分组成:<template>、<style>、<script><template>html&…...

    2024/4/14 13:12:01
  13. 利用mimikatz插件获取内网相关信息

    你宁愿错过也不愿意主动是吗。。。。---- 网易云热评环境:小攻:Kali 2020,ip:192.168.1.133小受:win7 x86,ip:192.168.1.137一、生成木马及监听主机参考上篇文章:二、利用mimikatz获取内网相关信息1、加载mimikatzmeterpreter > load kiwi2、查看帮助信息meterpret…...

    2024/4/14 13:12:16
  14. 在centos7上,安装mysql5.7 ,并修改时区

    在centos7上,本地安装mysql5.7 ,并修改时区 1.下载 MySQL yum包 wget http://repo.mysql.com/mysql57-community-release-el7-10.noarch.rpm2.安装MySQL源 rpm -Uvh mysql57-community-release-el7-10.noarch.rpm3.安装MySQL服务端,需要等待一些时间 yum install -y mysql-co…...

    2024/4/14 13:12:06
  15. CNN-Based Signal Detection for Banded Linear Systems

    基于CNN的信号检测宽带线性系统摘要介绍A.背景和动机B.贡献C.相关工作D.论文结构系统模型A.线性宽带系统B.近似宽带系统C.基于DNN的检测器结构基于CNN的检测器A.输入预处理B.CNN 摘要 宽带线性系统应用广泛却带来了ICI和ISI。设计了一套基于CNN的高准确率低复杂度的信号检测器,…...

    2024/4/14 13:13:27
  16. (蓝桥杯)蛇形矩阵的求法

    (蓝桥杯)蛇形矩阵的求法 说难也不难的一道题(通过率60%以上):题目描述:蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。输入: 本题有多组数据,每组数据由一个正整数N组成。(N不大于100)输出: 对于每一组数据,输出一个N行的蛇形矩阵。两组输出之间不要额外的…...

    2024/4/19 17:42:06
  17. 升级版快速排序——随机化快速排序

    随机化思想的引入 在数据结构这门课程的学习中,我们了解到一种名为快速排序的算法,该算法时间复杂度为O(nlog⁡2n)O(n\log_2 n)O(nlog2​n),但是,在课程中,书本和老师都指出了它的一个缺点:在数据有序时的时间复杂度为O(n2)O(n^2)O(n2) 为了“消除”这个缺点…...

    2024/4/16 6:54:25
  18. Lua:迭代器

    贴上一个链接,lua的知识很全 https://www.runoob.com/lua/lua-iterators.html 泛型for --举例 tab={"java","C++","C","Lua"} for key,value in ipairs(tab) do print(key,value) end首先,初始化,计算in后面的表达式的值(ipairs)…...

    2024/4/4 19:50:48
  19. CSS学习教程之简单入门

    层叠样式表(Cascading Style Sheet,简称:CSS)是为网页添加样式的代码。本学习教程主要介绍 CSS 的基础知识,并解答类似问题:怎样将文本设置为黑色或红色?怎样将内容显示在屏幕的特定位置?怎样用背景图片或颜色来装饰网页?做一个简单的入门。对于CSS的学习可以分为以下…...

    2024/4/25 10:07:41
  20. 是折叠表达式,不是可变参数

    学习地址 单独记录下来,免得老是找不到....

    2024/5/4 23:39:41

最新文章

  1. LeetCode题目115:不同子序列

    题目描述 给定一个字符串 s 和一个字符串 t &#xff0c;计算在 s 的子序列中 t 出现的个数。 一个字符串的子序列是指&#xff0c;通过删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符的相对位置形成的新字符串。&#xff08;例如&#xff0c;"ACE&…...

    2024/5/10 13:33:48
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/9 21:23:04
  3. 策略模式图

    策略模式 小小的图解 主要的三个角色 Strategy—抽象策略角色ConcreateStrategy—具体策略角色Context—上下文角色 封装了对具体策略的调用可以使用set的依赖注入也可以使用构造方法 核心是上下文角色 只要调用上下文角色就行&#xff0c;实现解耦 策略 工厂 将上下文角…...

    2024/5/8 7:01:36
  4. Stable Diffusion的界面参数详解

    Stable Diffusion作为一款强大的文本到图像生成模型,其界面参数是用户与模型进行交互的重要桥梁。这些参数不仅影响着模型的生成效果,还能够帮助用户更加精准地控制生成图像的风格、内容等。本文将详细介绍Stable Diffusion的界面参数,帮助用户更好地理解和应用这一工具。 …...

    2024/5/9 19:21:42
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/10 12:36:12
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/9 15:10:32
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/9 4:20:59
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/7 11:36:39
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/8 20:48:49
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/7 9:26:26
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/8 19:33:07
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/8 20:38:49
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/10 10:22:18
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/9 17:11:10
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57