精华内容
下载资源
问答
  • OpenCL将数组从内存copy到显存。在某种情况下可以作为一种可用的优化方案。
  • 02. Rust 内存管理 Copy & Clone(上)

    千次阅读 2018-12-15 08:47:00
    #[derive(Debug, Clone, Copy)] struct Point { x: f64 , y: f64 , } 复制代码 Rust 默认绑定变量是进行 move 行为, 想要保留 move 前的变量, 可以使用 clone 函数, 想要实现基本类型一样的 copy ...

    Clone

    Rust 语法上一个变量的值是转移给另一个变量, 但是有些情况下可能会想变量值转移之后, 自身还能继续使用. 可以使用 clone 函数

    let a = String::from("test");
    let b = a.clone();
    println!("{}", a);
    复制代码

    clone 这个函数是在标准库的 std::clone::Clone trait 里, 既然是个 trait, 也就意味着可以自己实现一套操作, 通常情况下用默认的定义就好了.

    Copy

    我们现在了解到每次绑定变量, 都会发生所有权转移, 但是你会发现写有些东西的时候好像行为跟目前的认知有点不一样.

    let a: i32 = 10;
    let b = a;
    println!("a = {}", a); // a = 10
    复制代码

    a 没有使用 clone 还能使用, 原因是 Rust 有部分类型默认实现了 std::marker::Copy trait. 像 structs 这类没有默认实现的类型, 想要这样就得实现一下 Copy.

    fn main() {
        let p1 = Point { x: 1.0, y: 1.0 };
        let p2 = p1;
        println!("p1 = {:?}", p1);
    }
    
    #[derive(Debug)]
    struct Point {
        x: f64,
        y: f64,
    }
    
    impl Copy for Point {}
    复制代码

    但是其实这样还是没法用的, 编译后就报错了, 因为 struct Point 没有实现 Clone trait.

    pub fn main_8_6() {
        let p1 = Point { x: 1.0, y: 1.0 };
        let p2: Point = p1;
        println!("p1 = {:?}", p1);
    }
    
    #[derive(Debug)]
    struct Point {
        x: f64,
        y: f64,
    }
    
    impl Clone for Point {
        fn clone(&self) -> Self {
            Self { x: self.x, y: self.y }
        }
    }
    
    impl Copy for Point {}
    复制代码

    现在终于好使了. 但是我们发觉做这些操作非常烦, 我们注意到 #[derive(Debug)] 这个东西, 刚好 Rust 提供了Clone, Copy 的属性.

    pub fn main_8_6() {
        let p1 = Point { x: 1.0, y: 1.0 };
        let p2: Point = p1;
        println!("p1 = {:?}", p1);
    }
    
    #[derive(Debug, Clone, Copy)]
    struct Point {
        x: f64,
        y: f64,
    }
    复制代码

    Rust 默认绑定变量是进行 move 行为, 想要保留 move 前的变量, 可以使用 clone 函数, 想要实现基本类型一样的 copy 行为, 我们可以添加 Clone, Copy 属性.

    展开全文
  • 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝),引用计数实现

    标准C++类std::string的内存共享,值得体会:

    详见大牛:https://www.douban.com/group/topic/19621165/

    顾名思义,内存共享,就是两个乃至更多的对象,共同使用一块内存;

    1.关于string的内存共享问题:

    通常,string类中必有一个私有成员,其是一个char*,用户记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存。

    因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的,string类在返回这块内存地址时,只返回const char*,也就是只读的,

    如果你要写,也只能通过string提供的方法进行数据的改写。

    #include<iostream>
    #include<string>
    #include<cstdio>
    using namespace std;
     
    main()
    {
           string str1 = "hello world";
           string str2 = str1;
           string str3 = str2;
      
           printf ("内存共享:\n");
           printf ("\tstr1 的地址: %x\n", (unsigned int)str1.c_str() );
           printf ("\tstr2 的地址: %x\n", (unsigned int)str2.c_str() );
           printf ("\tstr3 的地址: %x\n", (unsigned int)str3.c_str() );
    
           return 0;
    }
    如上例子中,str1,str2,str3共享同一块内存,如图:


    基本就是内存string类内存共享的最底层展现了,既然内存是一样的了,如果需要改写某个对象怎么办?由此引出写时拷贝Copy-On-Write

    2.关于Copy-On-Write(原理)

    顾名思义,写的时候在拷贝,(读的时候就不用了,哈哈)

    还是以上边的例子为例:

    #include<iostream>
    #include<string>
    #include<cstdio>
    using namespace std;
     
    main()
    {
           string str1 = "hello world";
           string str2 = str1;
           string str3 = str2;
      
           printf ("内存共享:\n");
           printf ("\tstr1 的地址: %x\n", (unsigned int)str1.c_str() );
           printf ("\tstr2 的地址: %x\n", (unsigned int)str2.c_str() );
           printf ("\tstr3 的地址: %x\n", (unsigned int)str3.c_str() );
    
           str3[1]='a';
           str2[1]='w';
           str1[1]='q';
      
           printf ("通过写时拷贝之后:\n");
           printf ("\tstr1 的地址: %x\n", (unsigned int)str1.c_str() );
           printf ("\tstr2 的地址: %x\n", (unsigned int)str2.c_str() );
           printf ("\tstr3 的地址: %x\n", (unsigned int)str3.c_str() );
    
           return 0;
    }
    
    //输出结果:
    内存共享:
      str1 的地址: 83f9017
      str2 的地址: 83f9017
      str3 的地址: 83f9017
    通过写时拷贝之后:
      str1 的地址: 83f9017
      str2 的地址: 83f9054
      str3 的地址: 83f9034
    很明显可以看出来,一开始,str1,str2,str3共享同一块内存,地址都是一样的;

    当开始修改是这些内存是,先不说如何实现,先表征是如何写时拷贝的,看图,咱还是看图:

    图中依然说明了str3的内容修改是怎么回事,str2的内容修改,也是同样的道理,重新给str2在堆上开辟空间,原空间只是str1一个人用,修改最后一个str1的内容时,

    当然就不用在和前两种一样啦,因为,这个时候,原空间只有str1一个人用,这个时候,对此空间操作,没有任何问题。都写都可以;

    写时拷贝在此例中的体现,主要是str2,和str3内容的修改;但是有没有发现,我每次开辟空间的同时,会在新开辟的空间开头多分配一个空间,存放的是count;

    原因就和写时拷贝的具体操作有关了:

    3.写时拷贝(Copy-On-Write)的实现:

    Copy-On-Write使用了“引用计数”,有一个变量count来计数,而且计数就放在没开辟一段空间的开头几个字节。

    当第一个类构造时,string的构造函数会根据传入的参数从堆上分配内存,当有其它类需要这块内存时,这个计数为自动累加,

    当有类析构时,这个计数会减一,直到最后一个类析构时,此时的count为1或是0,此时,程序才会真正的Free这块从堆上分配的内存。 

    下面是我写的一个简单的例子:

    #include<iostream>
    using namespace std;
    
    class String
    {
    public:
    	String(const char* str)
    		//初始时字符创有一个\0外加4个字节的引用计数空间
    		:_str(new char[strlen(str)+5])
    	{
    		(*((int*)_str)) = 1;//申请的空间赋值为1
    		_str += 4; //让_str还是指向字符创的第一个字符
    		           //而不是引用计数的头上
    		strcpy(_str,str);
    	}
    
    	String(const String& s)
    		:_str(s._str)
    	{
    		(*(((int*)_str) - 1)) += 1;
    	}
    
    	String& operator=(const String& s)
    	{
    		if(_str != s._str)
    		{
    			if(*(((int*)_str) - 1) == 0)
    			{
    				delete[] (_str-4);
    			}
    			_str = s._str;
    			*(((int*)_str) - 1) += 1;
    		}
    		return *this;
    
    
    	}
    	~String()
    	{
    		if(*(((int*)_str) - 1) == 0)
    		{
    			_str -= 4;
    			delete[] _str;
    		}
    	}
    private:
    	char *_str;
    };
    
    void Test()
    {
    	String s1("11111111111111111111111111");
    	String s2(s1);
    }
    
    int main()
    {
    	Test();
    	return 0;
    }
    在内存开头开辟引用计数空间;

    到此,string类的内存共享和写时拷贝,就算是告一段落了,个人拙见,跪求赐教!

    展开全文
  • Mat类的两个拷贝函数,copyTo()和clone(),都是进行深复制,也就是会另外开辟一个内存存储被复制的数据区域,对复制得到的新矩阵进行释放release()不会影响原矩阵的数据.  一般情况下使用copyTo函数进行图像...

    我们都知道OpenCV中存储图像常用的方法就是用Mat表示. 基本上讲 Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。矩阵头的尺寸是常数值,但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。

    基于这个考虑,OpenCV使用引用计数机制。其思路是让每个 Mat 对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则 只拷贝信息头和矩阵指针 ,而不拷贝矩阵。例如以下一段代码:

    Mat A, C;                                 // 只创建信息头部分
    A = cv::imread("test.jpg", CV_LOAD_IMAGE_COLOR); // 这里为矩阵开辟内存
    Mat B(A);                                 // 使用拷贝构造函数
    C = A;                                    // 赋值运算符

    以上代码中的所有Mat对象最终都指向同一个也是唯一一个数据矩阵。虽然它们的信息头不同,但通过任何一个对象所做的改变也会影响其它对象。实际上,不同的对象只是访问相同数据的不同途径而已。

    现在你也许会问,如果矩阵属于多个 Mat 对象,那么当不再需要它时谁来负责清理?简单的回答是:最后一个使用它的对象。通过引用计数机制来实现。无论什么时候有人拷贝了一个 Mat 对象的信息头,都会增加矩阵的引用次数;反之当一个头被释放之后,这个计数被减一;当计数值为零,矩阵会被清理。

    但某些时候你仍会想拷贝矩阵本身(不只是信息头和矩阵指针),这时可以使用函数 clone() 和我们即将讨论的函数 copyTo() 。如下:

    cv::Mat testImage = cv::imread("test.jpg"); //读入图片
    cv::Mat imageCopy; 
    testImage.copyTo(imageCopy); //完整拷贝一份testImage

    Mat类的两个拷贝函数,copyTo()和clone(),都是进行深复制,也就是会另外开辟一个内存存储被复制的数据区域,对复制得到的新矩阵进行释放release()不会影响原矩阵的数据. 

    一般情况下使用copyTo函数进行图像(或者矩阵)复制,变量被销毁,那么开辟的空间也会被Mat的析构函数释放. 但是如果copyTo函数的拷贝对象不是局部变量, 而是全局变量或者句柄指针,则出现变量一直存在而每一次复制都会开辟新的空间无法释放,造成内存泄露问题. 我们看一下以下例子, 例子是一个简单的循环队列, 队列元素包含Mat对象:

    队列头文件test_queue.h

    #ifndef __OPT_QUENE_H__
    #define __OPT_QUENE_H__
    
    #include <opencv2/opencv.hpp>
    #include <pthread.h>
    
    #define MAX_QUEUE_SIZE 100
    
    typedef struct output_rslt_tag
    {
       cv::Mat stImage;                               /* 帧图像 */
       unsigned int uiFrameSeq; 
    }Rslt_s;
    
    typedef struct queue_tag{
        int front;
        int rear;
        Rslt_s data[MAX_QUEUE_SIZE];
    
        pthread_mutex_t q_lock;
        pthread_cond_t cond;
    }stQueue_s;
    
    
    /* 初始化 */
    int queue_create(void **ppvHandle);
    
    /* 判断是否为空 */
    int queue_empty(void *pvHandle);
    
    /* 判断队列是否满 */
    int queue_full(void *pvHandle);
    
    /* 求循环队列的长度 */
    int queue_length(void *pvHandle);
    
    /* 入队 */
    int queue_push(void *pvHandle, Rslt_s *pstOptRslt);
    
    /* 队头元素出队,返回其值 */
    int queue_pop(void *pvHandle, Rslt_s *pstOptRslt);
    
    /* 销毁队列 */
    int queue_destroy(void *pvHandle);
    
    
    #endif //__OPT_QUENE_H__

    队列源文件: test_queue.cpp

    #include "test_queue.h"
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <cmath>
    
    
    int queue_create(void **ppvHandle)
    {
        stQueue_s* pstQueueInit;
        pstQueueInit = (stQueue_s*) malloc(sizeof(stQueue_s));
        if(pstQueueInit == NULL)
        {
            printf("Memory allocation error.\nQueue initialization failed.\n");
            return -1;
        }
    
        pstQueueInit->front = 0;
        pstQueueInit->rear = 0;
    
        
        /**thread lock initial**/
        pthread_mutex_init(&(pstQueueInit->q_lock), NULL);
        pthread_cond_init(&(pstQueueInit->cond), NULL);
    
        *ppvHandle = pstQueueInit;
        return 0;
    }
    
    int queue_empty(void *pvHandle)
    {
        stQueue_s* pstQueue = (stQueue_s*)pvHandle;
        /**Return 1 if empty**/
        if( pstQueue->front == pstQueue -> rear)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    
    }
    
    int queue_full(void *pvHandle)
    {
        stQueue_s* pstQueue = (stQueue_s*)pvHandle;
        /**Return 1 if full**/
        if(pstQueue->front == (pstQueue->rear + 1)%MAX_QUEUE_SIZE)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
    
    int queue_length(void *pvHandle)
    {
        stQueue_s* pstQueue = (stQueue_s*)pvHandle;
        return  (pstQueue->rear - pstQueue->front + MAX_QUEUE_SIZE)%MAX_QUEUE_SIZE;
    }
    
    int queue_push(void *pvHandle, Rslt_s *pstOptRslt)
    {
        stQueue_s* pstQueue = (stQueue_s*)pvHandle;
    
        if(pstQueue == NULL)
        {
            printf("Queue is not initialized, exit..\n");
            return -1;
        }
    
        if(pstOptRslt == NULL)
        {
            printf("Invalid INPUT element, exit..\n");
            return -1;
        }
    
        pthread_mutex_lock(&(pstQueue->q_lock));
    
        pstOptRslt->stImage.copyTo(pstQueue->data[pstQueue->rear].stImage); //拷贝图像
        pstQueue->data[pstQueue->rear].uiFrameSeq = pstOptRslt->uiFrameSeq;
        pstQueue->rear = (pstQueue->rear + 1)%MAX_QUEUE_SIZE;
    
        /**overwrite if queue is full**/
        if(pstQueue->rear == pstQueue->front)
        {
            pstQueue->front = pstQueue->rear + 1;
            printf("Warning: Data overwritten, Queue is full.. \n");
        }
    
        pthread_cond_signal(&(pstQueue->cond));
        pthread_mutex_unlock(&(pstQueue->q_lock));
    
        return 0;
    }
    
    int queue_pop(void *pvHandle, Rslt_s *pstOptRslt)
    {
        stQueue_s* pstQueue = (stQueue_s*)pvHandle;
    
        if(pstQueue->front == pstQueue->rear)
        {
            printf("Empty queue, exit..\n");
            pthread_mutex_unlock(&pstQueue->q_lock);
            return AIA_FAIL;
        }
    
        if(pstOptRslt == NULL)
        {
            printf("Invalid INPUT element, exit.. \n");
            return AIA_FAIL;
        }
    
        pthread_mutex_lock(&pstQueue->q_lock);
    
        (pstQueue->data)[pstQueue->front].stImage.copyTo(pstOptRslt->stImage);
        pstOptRslt->uiFrameSeq = (pstQueue->data)[pstQueue->front].uiFrameSeq;
    
        pstQueue->front = (pstQueue->front + 1)%MAX_QUEUE_SIZE;
    
        pthread_mutex_unlock(&(pstQueue->q_lock));
    
        return 0;
    }
    
    int queue_destroy(void *pvHandle)
    {
        stQueue_s* pstQueue = (stQueue_s*)pvHandle;
        if(pstQueue != NULL)
        {
            pthread_mutex_destroy(&(pstQueue->q_lock));
            pthread_cond_destroy(&(pstQueue->cond));
            free(pstQueue);
            pstQueue = NULL;
        }
        return 0;
    }

    在queue_push()函数中,pstOptRslt->stImage.copyTo(pstQueue->data[pstQueue->rear].stImage); 直接想句柄指针指向的数组内容拷贝数据,这个数据是在数组之外的空间中申请的新空间,而且由于句柄指针一直存在,这个空间不会释放,直到程序结束. 因此随着程序的持续运行, 不断的进行入队操作, 占用的空间会越来越大,造成内存泄露.

    展开全文
  • CUDA零拷贝内存(zerocopy memory)

    千次阅读 2017-11-29 16:07:25
    为了实现CPU与GPU内存的共享,cuda采用了零拷贝内存,它值固定内存的一种,当然,也就是实际存储空间实在cpu上。 零拷贝内存的延迟高,在进行频繁的读写操作时尽量少用,否则会大大降低性能。 /* *创建固定内存...

    为了实现CPU与GPU内存的共享,cuda采用了零拷贝内存,它值固定内存的一种,当然,也就是实际存储空间实在cpu上。

    零拷贝内存的延迟高,在进行频繁的读写操作时尽量少用,否则会大大降低性能。

    /*
     *创建固定内存映射
     *
     * flags:   cudaHostAllocDefault:      make cudaHostAlloc same as "cudaMallocHost"
     *          cudaHostAllocPortable:     函数返回能被所有cuda上下文使用的固定内存,而不仅仅是执行内存分配的那个
     *          cudaHostAllocWriteCombined:返回写结合的内存,该内存可以在某个系统配置上通过PCIe总线上更快的传输
     *          cudaHostAllocMapped:       该标志返回映射到的设备内存地址空间的主机内存
     */
        cudaError_t cudaHostAlloc(void **pHost, size_t count, unsigned int flags);

    /*
     *
     * 获取映射得到的固定内存的设备指针
     */
        cudaError_t cudaHostGetDevicePointer(void **pDevice, void *pHost, unsigned int flags);

    整体的使用过程:

        size_t nBytes = 2048;
        float *h_A;
        h_A = (float *)malloc(nBytes);
        initialData(h_A, nBytes);
        cudaHostAlloc((void **)&h_A, nBytes, cudaHostAllocMapped);
        cudaHostGetDevicePointer((void **)&d_A, (void *)h_A, 0);
        cudaFreeHost(h_A);


    给个完整程序,源码网址: 点击打开链接
    #include "../common/common.h"
    #include <cuda_runtime.h>
    #include <stdio.h>
    
    /*
     * This example demonstrates the use of zero-copy memory to remove the need to
     * explicitly issue a memcpy operation between the host and device. By mapping
     * host, page-locked memory into the device's address space, the address can
     * directly reference a host array and transfer its contents over the PCIe bus.
     *
     * This example compares performing a vector addition with and without zero-copy
     * memory.
     */
    
    void checkResult(float *hostRef, float *gpuRef, const int N)
    {
        double epsilon = 1.0E-8;
    
        for (int i = 0; i < N; i++)
        {
            if (abs(hostRef[i] - gpuRef[i]) > epsilon)
            {
                printf("Arrays do not match!\n");
                printf("host %5.2f gpu %5.2f at current %d\n", hostRef[i],
                        gpuRef[i], i);
                break;
            }
        }
    
        return;
    }
    
    void initialData(float *ip, int size)
    {
        int i;
    
        for (i = 0; i < size; i++)
        {
            ip[i] = (float)( rand() & 0xFF ) / 10.0f;
        }
    
        return;
    }
    
    void sumArraysOnHost(float *A, float *B, float *C, const int N)
    {
        for (int idx = 0; idx < N; idx++)
        {
            C[idx] = A[idx] + B[idx];
        }
    }
    
    __global__ void sumArrays(float *A, float *B, float *C, const int N)
    {
        int i = blockIdx.x * blockDim.x + threadIdx.x;
    
        if (i < N) C[i] = A[i] + B[i];
    }
    
    __global__ void sumArraysZeroCopy(float *A, float *B, float *C, const int N)
    {
        int i = blockIdx.x * blockDim.x + threadIdx.x;
    
        if (i < N) C[i] = A[i] + B[i];
    }
    
    int main(int argc, char **argv)
    {
        // set up device
        int dev = 0;
        CHECK(cudaSetDevice(dev));
    
        // get device properties
        cudaDeviceProp deviceProp;
        CHECK(cudaGetDeviceProperties(&deviceProp, dev));
    
        // check if support mapped memory
        if (!deviceProp.canMapHostMemory)
        {
            printf("Device %d does not support mapping CPU host memory!\n", dev);
            CHECK(cudaDeviceReset());
            exit(EXIT_SUCCESS);
        }
    
        printf("Using Device %d: %s ", dev, deviceProp.name);
    
        // set up data size of vectors
        int ipower = 10;
    
        if (argc > 1) ipower = atoi(argv[1]);
    
        int nElem = 1 << ipower;
        size_t nBytes = nElem * sizeof(float);
    
        if (ipower < 18)
        {
            printf("Vector size %d power %d  nbytes  %3.0f KB\n", nElem, ipower,
                   (float)nBytes / (1024.0f));
        }
        else
        {
            printf("Vector size %d power %d  nbytes  %3.0f MB\n", nElem, ipower,
                   (float)nBytes / (1024.0f * 1024.0f));
        }
    
        // part 1: using device memory
        // malloc host memory
        float *h_A, *h_B, *hostRef, *gpuRef;
        h_A     = (float *)malloc(nBytes);
        h_B     = (float *)malloc(nBytes);
        hostRef = (float *)malloc(nBytes);
        gpuRef  = (float *)malloc(nBytes);
    
        // initialize data at host side
        initialData(h_A, nElem);
        initialData(h_B, nElem);
        memset(hostRef, 0, nBytes);
        memset(gpuRef,  0, nBytes);
    
        // add vector at host side for result checks
        sumArraysOnHost(h_A, h_B, hostRef, nElem);
    
        // malloc device global memory
        float *d_A, *d_B, *d_C;
        CHECK(cudaMalloc((float**)&d_A, nBytes));
        CHECK(cudaMalloc((float**)&d_B, nBytes));
        CHECK(cudaMalloc((float**)&d_C, nBytes));
    
        // transfer data from host to device
        CHECK(cudaMemcpy(d_A, h_A, nBytes, cudaMemcpyHostToDevice));
        CHECK(cudaMemcpy(d_B, h_B, nBytes, cudaMemcpyHostToDevice));
    
        // set up execution configuration
        int iLen = 512;
        dim3 block (iLen);
        dim3 grid  ((nElem + block.x - 1) / block.x);
    
        sumArrays<<<grid, block>>>(d_A, d_B, d_C, nElem);
    
        // copy kernel result back to host side
        CHECK(cudaMemcpy(gpuRef, d_C, nBytes, cudaMemcpyDeviceToHost));
    
        // check device results
        checkResult(hostRef, gpuRef, nElem);
    
        // free device global memory
        CHECK(cudaFree(d_A));
        CHECK(cudaFree(d_B));
    
        // free host memory
        free(h_A);
        free(h_B);
    
        // part 2: using zerocopy memory for array A and B
        // allocate zerocpy memory
        CHECK(cudaHostAlloc((void **)&h_A, nBytes, cudaHostAllocMapped));
        CHECK(cudaHostAlloc((void **)&h_B, nBytes, cudaHostAllocMapped));
    
        // initialize data at host side
        initialData(h_A, nElem);
        initialData(h_B, nElem);
        memset(hostRef, 0, nBytes);
        memset(gpuRef,  0, nBytes);
    
        // pass the pointer to device
        CHECK(cudaHostGetDevicePointer((void **)&d_A, (void *)h_A, 0));
        CHECK(cudaHostGetDevicePointer((void **)&d_B, (void *)h_B, 0));
    
        // add at host side for result checks
        sumArraysOnHost(h_A, h_B, hostRef, nElem);
    
        // execute kernel with zero copy memory
        sumArraysZeroCopy<<<grid, block>>>(d_A, d_B, d_C, nElem);
    
        // copy kernel result back to host side
        CHECK(cudaMemcpy(gpuRef, d_C, nBytes, cudaMemcpyDeviceToHost));
    
        // check device results
        checkResult(hostRef, gpuRef, nElem);
    
        // free  memory
        CHECK(cudaFree(d_C));
        CHECK(cudaFreeHost(h_A));
        CHECK(cudaFreeHost(h_B));
    
        free(hostRef);
        free(gpuRef);
    
        // reset device
        CHECK(cudaDeviceReset());
        return EXIT_SUCCESS;
    }


    展开全文
  • 内存管理语句的assign、retain、copy、multableCopy等特性,做了一个差异对比和分析。
  • NIO效率高的原理之零拷贝与直接内存映射

    万次阅读 多人点赞 2019-07-31 08:00:00
    首先澄清,零拷贝与内存直接映射并不是Java中独有的概念,并且这两个技术并不是等价的。 零拷贝 零拷贝是指避免在用户态(User-space) 与内核态(Kernel-space) 之间来回拷贝数据的技术。 传统IO 传统IO读取数据并...
  • 通过对C#文档中Array.Copy()和Buffer.BlockCopy()两个方法的整理,深刻理解其运行原理及实现方式。在理解了Array.Copy()之后,从而对List<T>的拷贝、插入、删除操作实现,有一个更深入的理解。 一、Array....
  • C# 内存复制和数组复制示例

    千次阅读 2018-03-22 16:55:54
    内存复制-Marshal.Copy: // 复制当前传入的数据 byte[] pcm_src = new byte[len]; // 复制数据到二进制数组 Marshal.Copy(pcm, pcm_src, 0, len);数组复制-Array.Copy:// 复制当前传入的数据 byte[] pcm_src = ...
  • python 多进程 内存 copy-on-write

    千次阅读 2015-09-29 10:19:08
    由于python 中有个GIL 的东西,所使用的线程 python线程对于 cpu密集型的应用是没有作用的 对于io...每次启动子进程,子进程初始内存大小和启动时刻主进程内存大小一样。这个是linux fork机制。 问题2: 当子进程没
  • php手动释放内存

    千次阅读 2017-11-22 21:44:25
    关于php释放内存问题
  • ZeroCopy高性能零拷贝(DMA)

    千次阅读 2020-05-03 15:58:03
    操作系统的核心是内核,独立于分内核应用程序,可以访问受保护的内存空间,也可以访问底层硬件设备。 为了避免用户进程直接操作内核,保证内核安全,操作系统将虚拟内存划分为两部分,一部分是内核空间(Kernel-space...
  • DMA copy和CPU copy

    千次阅读 2020-05-14 23:02:15
    直接内存访问,是一种无需CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制。使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。DMA方式的数据传输由DMA控制器...
  • c++ memcpy内存拷贝

    千次阅读 2018-02-25 15:17:06
    memcpy指的是c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中 下面是游戏开发中的一个具体的应用: FR:徐海涛(hunk...
  • python模块 - copy模块

    万次阅读 2015-05-18 23:16:05
    该模块只提供了两个主要的方法:copy.copycopy.deepcopy,分别表示浅复制与深复制。 直接赋值,深拷贝和浅拷贝的区别 直接赋值:简单地拷贝对象的引用,两个对象的id相同。就是对象的引用(别名),就是给...
  • Copy On Write机制了解一下

    万次阅读 多人点赞 2019-05-15 17:29:50
    执行BGSAVE命令或者BGREWRITEAOF命令的过程中,Redis需要创建当前服务器进程的子进程,而大多数操作系统都采用写时复制(copy-on-write)来优化子进程的使用效率,所以在子进程存在期间,服务器会提高负载因子的阈值...
  • numpy.copy详解

    千次阅读 2020-01-12 23:34:12
    numpy.copy 用例: numpy.copy(a, order=‘K’) ...控制拷贝数组在内存中的存储顺序。'C’表示C顺序,'F’表示F顺序,如果输入数组是连续值,那么’A’亦为F顺序,若输入数组不是连续值...
  • copy_to_user和copy_form_user函数分析

    千次阅读 2018-07-21 14:46:19
    学习驱动比较常用的两个函数,copy_to_user和copy_form_user。   因为传参都是传的地址,单因为内核空间不能直接访问用户空间的内存,所以内核空间要使用用户空间参数。必须进行地址转换。而这连个函数就是负责把...
  • 日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 Linux-4.7 X86 & arm ... Linux内存管理 http://blog.csdn.net/vanbreaker/article/details/75799411 前景回顾前面我们讲到服务器体系(SMP, NUMA, M
  • 关于WM_COPYDATA的使用总结

    千次阅读 2019-11-05 14:07:01
    windows进程间通信的方法... 本人最近在项目中使用了WM_COPYDATA来作为进程间通信的方式,于是就有了这篇总结博客。 首先,关于WM_COPYDATA的介绍可以查看:https://docs.microsoft.com/zh-cn/windows/win32/datax...
  • 结构体copy问题

    千次阅读 2019-10-29 17:57:45
    结构体copy问题 c语言中,结构使用是非常频繁的,操作结构体时,我们一般使用memcpy...使用memcpy对结构体进行内存copy,首先要知道结构体的大小计算,最简单的方法使用sizeof(结构体类型)进行计算。当然,本文也介绍...
  • 一文了解 Redis 内存监控和内存消耗

    千次阅读 2019-10-15 22:58:30
    Redis 是一种内存数据库,将数据保存在内存中,读写效率要比传统的将数据保存在磁盘上的数据库要快很多。所以,监控 Redis 的内存消耗并了解 Redis 内存模型对高效并长期稳定使用 Redis 至关重要。 内存使用统计 ...
  • 内存COPY ON WRITE机制

    万次阅读 2011-07-15 17:29:32
    刚了解到。赶快记下来。每个程序都有自己的数据段,代码段。。。补充:dll有自己的数据段,但没有自己的堆栈。...就是因为 内存COPY ON WRITE 机制程序1调用这个dll,运行过程中,dll的数据段肯定会改变,那内存
  • 解决Nexus3.xx版本的内存问题 楼主买了个1核1G的云服务器,准备搭建一个私服用一用,谁知竟然启动报错。 查看运行状态 说的很清楚,说我的内存不足。 ubuntu@10-9-17-59:~/Develop/Nexus/nexus-3.15.2-01/bin$ ./...
  • 含CPU与GPU间的内存copy,异步inference,2. 内存零copy, 异步inference, 3. 内存零copy, 同步inference 含CPU与GPU间的内存copy,异步inference 大多代码都用的是这种方式 先声明一个input和output数组, static ...
  • 首先声明OC的内存管理机制:引用计数。当一个对象的引用计数为0时,这个对象就会被释放。铭记以上两点,我们开始来探讨。 换句话说,如果一个对象,没有强指针指向,就会被释放。举个很形象的例子,假如每一个对象都...
  • Python中copy,deepcopy,=之深拷贝浅拷贝使用详解

    万次阅读 多人点赞 2018-08-30 12:10:29
    浅拷贝和深拷贝的区别是:浅拷贝只是将原对象在内存中引用地址拷贝过来了。让新的对象指向这个地址。而深拷贝是将这个对象的所有内容遍历拷贝过来了,相当于跟原来没关系了,所以如果你这时候修改原来对象的值跟他...
  • OpenCL中的内置函数async_work_group_copy和async_work_group_strided_copy用于实现全局内存(global memory)和本地内存(local memory)之间的异步数据复制,在某些情况下,使用异步复制(async copy)的方式在全局内存...
  • NSstring为什么使用copy copy的深度解析

    千次阅读 2018-04-27 17:23:37
    面试中经常问到的一个题,如果只是答到copy就是会单独复制一份,重新开辟一个地址空间。不会因为原值的修改而修改。这样回答100分只是拿到了10分。面试官会进一步追问。直到问到你不会。。。入门的回答以后,递进...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 428,163
精华内容 171,265
关键字:

内存copy低