Spiceserver内存操作相关函数的使用

Spiceserver内存操作部分也是整个项目用的比较多的模块,它自己封装了一套内存操作的函数,要掌握Spiceserver必须要掌握这些函数的使用,本篇我主要介绍一下我在阅读和使用这些函数及宏的一些理解,可能不是很全面,甚至理解不是很到位,后面有新的理解和发现再对blog进行更新。

内存操作底层相关函数

void *spice_malloc(size_t n_bytes) SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE(1);
void *spice_malloc0(size_t n_bytes) SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE(1);
void *spice_realloc(void *mem, size_t n_bytes) SPICE_GNUC_WARN_UNUSED_RESULT;
void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes) SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE2(1,2);
void *spice_malloc_n_m(size_t n_blocks, size_t n_block_bytes, size_t extra_size) SPICE_GNUC_MALLOC;
void *spice_malloc0_n(size_t n_blocks, size_t n_block_bytes) SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE2(1,2);
void *spice_realloc_n(void *mem, size_t n_blocks, size_t n_block_bytes) SPICE_GNUC_WARN_UNUSED_RESULT;

有关gcc编译优化

我们看到上面一些自定义内存分配函数都有两个修饰的宏,一个是SPICE_GNUC_MALLOC一个是SPICE_GNUC_ALLOC_SIZE(1)或或者SPICE_GNUC_MALLOC SPICE_GNUC_ALLOC_SIZE2(1,2),他们的定义如下:

#define SPICE_GNUC_MALLOC __attribute__((__malloc__))
#define SPICE_GNUC_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
#define SPICE_GNUC_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y)))

有关这些宏的定义在https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html中可以找到。

   __attribute__((__malloc__)) 的作用,英文解释如下:

意思是函数声明了这个以后,gcc对该函数有个更好的优化,意思是函数要返回一个指针,并且保证这个指针不含有别名,也就是指针指向的内存不被其他指针所指向,表明是要新分配一个内存。

__attribute__((__alloc_size__(x))) 英文解释如下:

意思是函数声明这个后,返回一个指向内存的指针,内存的大小有第x个函数参数制定,例如:void *spice_malloc(size_t n_bytes)使用声明该属性后,返回的内存大小被第1个参数指定,也就是n_bytes指定。

 
__attribute__((__alloc_size__(x,y)))
  英文解释如下:

同上面的差不多,只不过多了个参数,意思是返回内存大小同第x个参数和第y个参数有关,这个无需再解释了。

函数内部调用

阅读了源码,发现这些函数内部的调用都是比较简单的:

(1)spice_malloc:内部调用malloc函数,我们可以直接把它当做malloc来调用;

(2)spice_malloc0:内部调用的是calloc,它和malloc的区别是calloc分配内存后会将内存块清零;

(3)spice_realloc:内部调用realloc;

(4)spice_malloc_n:内部调用的是spice_malloc,只是参数分成两个,一个是块的大小,一个是块的个数;

(5)spice_malloc0_n:spice_malloc_n分配后再清零的效果;

(6)spice_malloc_n_m:在spice_malloc_n的基础上再增加一个额外的大小,例如:有时候我们分配内存时需要再加上一个结构体头部;

(7)spice_realloc_n:spice_realloc分配内存大小分成块和块数的形式。

我们来看下spice_malloc函数源码吧,其他函数都差不多,就不一一列举了。

void *spice_malloc(size_t n_bytes)
{
    void *mem;

    if (SPICE_LIKELY(n_bytes)) {/* 用于判断n_bytes是不是不等于0 */
        mem = malloc(n_bytes);

        if (SPICE_LIKELY(mem != NULL)) {/* 分配内存不等于NULL */
            return mem;
        }

        MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
    }
    return NULL;
}

内存块的使用Demo

Spiceserver中比较常用的内存块结构:RedDataChunk、SpiceChunks,我这里简单写了一个有关它们使用的Demo,我先将一个文件内容读取到RedDataChunk结构中,然后将RedDataChunk结构中的数据拷贝到SpiceChunks中,使用了Spiceserver中的一些自定义函数,代码如下:

#include <unistd.h>
#include <stdio.h>
#include "mem.h"
#define PACKAGE_LEN 512

/* 读取文件,将文件内容保存在red_chunk中 */
void get_chunk_from_file(const char *filepath, RedDataChunk *red_chunk)
{
    FILE *file = fopen("./test.txt", "rb");
    if( file == NULL ){
        return;
    }
    RedDataChunk *cur_chunk = red_chunk;
    while(TRUE){
        uint8_t *pBuff = spice_malloc0(PACKAGE_LEN+1);/* 分配内存 */
        if( pBuff == NULL ){
            break;
        }
        uint32_t read_len = fread(pBuff, 1, PACKAGE_LEN, file);
        if( read_len > 0 ){
            RedDataChunk *chunk = spice_new(RedDataChunk, 1);
            chunk->data_size = read_len;
            chunk->data = pBuff;
            chunk ->prev_chunk = cur_chunk;
            chunk->next_chunk = NULL;

            cur_chunk->next_chunk = chunk;
            cur_chunk = chunk;
        }
        else{/* 未能读到数据 */
            free(pBuff);
            break;
        }
    }

    fclose(file);
}

/* 释放RedDataChunk结构内存 */
void free_red_chunk(RedDataChunk *red_chunk)
{
    RedDataChunk *cur_chunk = red_chunk->next_chunk;
    RedDataChunk *next_chunk;

    while(cur_chunk){
        next_chunk = cur_chunk->next_chunk;
        free(cur_chunk);
        cur_chunk = next_chunk;
    }
}

/* 将保存在red_chunk中的数据拷贝到spice_chunks中 */
SpiceChunks *get_spicechunk(RedDataChunk *red_chunk)
{
    int i;
    SpiceChunks *data;
    RedDataChunk *chunk;
    /* 计算RedDataChunk块的个数注意要去除头结点 */
    for (i = 0, chunk = red_chunk->next_chunk; chunk != NULL; chunk = chunk->next_chunk) {
        i++;
    }
    data = spice_chunks_new(i);/* 分配SpiceChunks内存 */
    data->data_size = 0;
    data->flags |= SPICE_CHUNKS_FLAGS_FREE;
    for (i = 0, chunk = red_chunk->next_chunk;
         chunk != NULL && i < data->num_chunks;
         chunk = chunk->next_chunk, i++) {
        data->chunk[i].data  = chunk->data;
        data->chunk[i].len   = chunk->data_size;
        data->data_size     += chunk->data_size;
    }
    return data;
}

void print_chunks(SpiceChunks *chunks)
{
    int i;
    for(i=0; i<chunks->num_chunks; i++){
        printf("%s", chunks->chunk[i].data);
    }
}

int main(int argc, char **argv)
{
    RedDataChunk red_chunks;
    get_chunk_from_file( "./test.txt", &red_chunks );
    SpiceChunks *spice_chunks = get_spicechunk(&red_chunks);
    free_red_chunk(&red_chunks);
    print_chunks(spice_chunks);/* 打印 */
    spice_chunks_destroy(spice_chunks);
    return 0;
}
时间: 2024-11-05 22:58:19

Spiceserver内存操作相关函数的使用的相关文章

第41课 内存操作经典问题分析一

1. 野指针 (1)指针变量中的值是非法的内存地址,进而形成野指针 (2)野指针不是NULL指针,是指向不可用内存地址的指针 (3)NULL指针并无危害,很好判断,也很好调试 (4)C语言中无法判断一个指针所保存的地址是否合法 2. 野指针的由来 (1)局部指针变量没有被初始化 (2)指针所指向的变量在指针之前被销毁 (3)使用己经释放过的指针 (4)进行了错误的指针运算 (5)进行了错误的强制类型转换 [实例分析]野指针初探 #include <stdio.h> #include <m

Delphi中复制带有String的记录结构时不能使用Move之类的内存操作函数

请看下面的代码: program TestRecord; {$APPTYPE CONSOLE} uses  SysUtils,  Math; type  TRecordA = record    Name: string;  end; procedure RunTestRecord;var  R1, R2: TRecordA;begin  R1.Name := StringOfChar('A', RandomRange(64, 256) * 1024);  Move(R1, R2, SizeOf

【转】《深入理解计算机系统》C程序中常见的内存操作有关的典型编程错误

原文地址:http://blog.csdn.net/slvher/article/details/9150597 对C/C++程序员来说,内存管理是个不小的挑战,绝对值得慎之又慎,否则让由上万行代码构成的模块跑起来后才出现内存崩溃,是很让人痛苦的.因为崩溃的位置在时间和空间上,通常是在距真正的错误源一段距离之后才表现出来.前几天线上模块因堆内存写越界1个字节引起各种诡异崩溃,定位问题过程中的折腾仍历历在目,今天读到<深入理解计算机系统>第9章-虚拟存储器,发现书中总结了C程序中常见的内存操作有

IO-05内存操作流06管道流

JAVA中可以将输出的位置设置在内存上,此时使用ByteArrayInputStream,ByteArrayOutputStream来完成输入,输出功能. 利用这两个类实现大小字母的转换: package lianxijihe; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; impo

Java并发编程--7.Java内存操作总结

主内存和工作内存 工作规则 Java内存模型, 定义变量的访问规则, 即将共享变量存储到内存和取出内存的底层细节  所有的变量都存储在主内存中,每条线程有自己的工作内存,工作内存中用到的变量, 是从主内存拷贝的副本,线程对变量的所有操作都在工作内存中进行, 线程间变量值得传递均需通过主内存来完成 内存间交互操作 1.luck(锁定):作用于主内存的变量,它把一个变量标示为一条线程独占的状态. 2.unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其

第42课 内存操作经典问题分析二

1. 常见内存错误 (1)结构体成员指针未初始化 (2)结构体成员指针未分配足够的内存 (3)内存分配成功,但并未初始化 (4)内存操作越界 [实例分析]常见的内存错误1 #include <stdio.h> #include <malloc.h> void test(int* p, int size) //对内存操作时,有带长度信息 { int i = 0; for(i = 0; i<size; i++) { printf("%d\n",p[i]); }

linux内存操作--ioremap和mmap学习笔记

最近在做视频输出相关的东西,对于预留给framebuffer的内存使用不是很清楚,现在找到一些资料整理一下,以备使用. 对于一个系统来讲,会有很多的外设,那么这些外设的管理都是通过CPU完成.那么CPU在这个过程中是如何找到外设的呢? 尽管在一个系统中会有诸多的外设,在每个外设的接口电路中会有多个端口.但是如果系统能够每个端口都被赋予一个具体的地址值,那么在系统中就能轻易的找到任何一个外设.系统在管理的时候,不管是内存还是外设都需要分配一个内存地址.对于一个32bit的系统来讲,可寻址的范围为2

JAVA的IO操作:内存操作流

掌握内存操作流 输入和输出都是从文件中来的,当然,也可将输出的位置设置在内存上,这就需要ByteArrayInputStream和ByteArrayOutputStream ByteArrayInputStream:将内容写入到内存中, ByteArrayOutputStream:将内存中数据输出 此时的操作应该以内存为操作点. 利用此类 完成一些功能. 常用方法 ByteArrayInputStream :是InputStream子类. public class ByteArrayInputS

Java API —— IO流(数据操作流 &amp; 内存操作流 &amp; 打印流 &amp; 标准输入输出流 &amp; 随机访问流 &amp; 合并流 &amp; 序列化流 &amp; Properties &amp; NIO)

1.操作基本数据类型的流 1) 操作基本数据类型 · DataInputStream:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型.应用程序可以使用数据输出流写入稍后由数据输入流读取的数据. · DataOutputStream:数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中.然后,应用程序可以使用数据输入流将数据读入. package datastreamdemos; import java.io.*; /** * Created b