linux和windows实现使用虚拟内存的解决方法

  1. 抛出windows下使用虚拟内存的方式:
mmap是posix标准下的一个函数,它将文件或设备的访问映射到内存中。下面的代码摘自ngx_rtmp_mp4_module.c,nginx的rtmp模块用它来从服务的录制的mp4文件中读取,以rtmp媒体流的形式分发给播放端。这样做可能是由于mp4的atom读取通过文件read和seek的操作不如直接内存映射后来的方便吧。它的给出了win32和linux下的不同实现:

#if (NGX_WIN32)
static void *
ngx_rtmp_mp4_mmap(ngx_fd_t fd, size_t size, off_t offset, ngx_fd_t *extra)
{
    void           *data;

    *extra = CreateFileMapping(fd, NULL, PAGE_READONLY,
                               (DWORD) ((uint64_t) size >> 32),
                               (DWORD) (size & 0xffffffff),
                               NULL);
    if (*extra == NULL) {
        return NULL;
    }

    data = MapViewOfFile(*extra, FILE_MAP_READ,
                         (DWORD) ((uint64_t) offset >> 32),
                         (DWORD) (offset & 0xffffffff),
                         size);

    if (data == NULL) {
        CloseHandle(*extra);
    }

    /*
     * non-NULL result means map view handle is open
     * and should be closed later
     */

    return data;
}


static ngx_int_t
ngx_rtmp_mp4_munmap(void *data, size_t size, ngx_fd_t *extra)
{
    ngx_int_t  rc;

    rc = NGX_OK;

    if (UnmapViewOfFile(data) == 0) {
        rc = NGX_ERROR;
    }

    if (CloseHandle(*extra) == 0) {
        rc = NGX_ERROR;
    }

    return rc;
}

#else

static void *
ngx_rtmp_mp4_mmap(ngx_fd_t fd, size_t size, off_t offset, ngx_fd_t *extra)
{
    void  *data;

    data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset);

    /* valid address is never NULL since there's no MAP_FIXED */

    return data == MAP_FAILED ? NULL : data;
}


static ngx_int_t
ngx_rtmp_mp4_munmap(void *data, size_t size, ngx_fd_t *extra)
{
    return munmap(data, size);
}

#endif

可以看出在windows下使用的是CreateFileMapping和MapViewOfFile,实际上还有一个函数OpenFileMapping,在windows下用这几个函数可以实现不同进程之间的共享内存,同时也要配合同步的对象来实现。

  1. 实现例子:
在linux上, 用mmap这个方法:
  www.2cto.com  
 1 int dumpFileDescriptor = open(mmFileName, O_CREAT | O_RDWR, 0755);
 2                                                                                    
 3 if(dumpFileDescriptor != -1)
 4 {
 5     void* mappedFileAddress = mmap(NULL,
 6                     MMAP_ALLOCATOR_SIZE,
 7                     PROT_READ | PROT_WRITE,
 8                     MAP_SHARED,
 9                     dumpFileDescriptor,
10                     0);
11 }
12                                                   
13 // Do something use mappedFileAddress
 
函数msysc可以保证把数据同步到了磁盘上
1 msync(mappedFileAddress, MMAP_ALLOCATOR_SIZE, MS_SYNC);
等不用的时候,用unmap函数解除映射
1 munmap(mappedFileAddress, MMAP_ALLOCATOR_SIZE);
然后可以用unlink把映射文件删掉,如果需要的话
1 unlink(mmFileName);  www.2cto.com  
同时我在网上搜了一下,windows下面用CreateFileMapping
 
 HANDLE dumpFileDescriptor = CreateFileA(mmFileName,
                        GENERIC_READ | GENERIC_WRITE,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       NULL,
                      OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       NULL);
 HANDLE fileMappingObject = CreateFileMapping(dumpFileDescriptor,
                      NULL,
                      PAGE_READWRITE,
                    0,
                  0,
                  NULL);
 void* mappedFileAddress = MapViewOfFile(fileMappingObject,
                     FILE_MAP_ALL_ACCESS,
                    0,
                    0,
                     MMAP_ALLOCATOR_SIZE);
                                                 
   // Do something use mappedFileAddress
 
同步数据到磁盘
1 FlushViewOfFile(mappedFileAddress, MMAP_ALLOCATOR_SIZE);
解除映射  www.2cto.com  
1 UnmapViewOfFile(mappedFileAddress);
Windows上如果想要删除映射文件的话,要先把文件Handle关掉,我一开始不知道这个,怎么删也删不掉。
1 CloseHandle(fileMappingObject);
2 CloseHandle(dumpFileDescriptor);
3 unlink(mmFileName);
 
两个平台跑起来的效果稍有差别,win32上假如你在heap上申请50M内存(别的什么也不干),把这50M映射了以后可以发现,程序运行时程序占用内存只有几百K,也就是说映射了的内存就跑到磁盘中去了,不占内存空间了,前提是你没有访问这50M空间。Linux上同样的程序,50M还会在内存中,即使你没有访问过它也会在内存里有备份,但是如果你申请的内存很大,比如100M,200M的时候才会释放掉内存空间。我想可能原因是在linux上,只有内存真正不够用时,系统才会把映射到文件中的内存空间释放吧,而windows上只要映射了文件,那么就会释放掉内存,除非你访问它。
  1. 可以获得总结:在windows上使用创建文件内存映射的方式其实跟创建管道是差不多的。下面为windows下创建管道的例子:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#define BUFSIZE 512

LPCSTR lpvMessage = TEXT("Default message from client.");
LPCSTR lpszPipename = TEXT("\\\\.\\pipe\\ACpipe");
int main()
{
	HANDLE hPipe = NULL;
	TCHAR  chBuf[BUFSIZE];
	BOOL   fSuccess = FALSE;
	DWORD  cbRead, cbToWrite, cbWritten;

	// Try to open a named pipe; wait for it, if necessary. 

reStart:
	while (!m_bIsStopLoop)	//此处的循环变量可以设置一个合理的值
	{
		hPipe = CreateFile(
			lpszPipename,   // pipe name 
			GENERIC_READ |  // read and write access 
			GENERIC_WRITE,
			0,              // no sharing 
			NULL,           // default security attributes
			OPEN_EXISTING,  // opens existing pipe 
			0,              // default attributes 
			NULL);          // no template file 

	  // Break if the pipe handle is valid. 

		if (hPipe != INVALID_HANDLE_VALUE)
			break;

		// Exit if an error other than ERROR_PIPE_BUSY occurs. 

		if (GetLastError() != ERROR_PIPE_BUSY)
		{
			_tprintf(TEXT("Could not open pipe. GLE=%d\n"), GetLastError());
			continue;
		}

		// All pipe instances are busy, so wait for 20 seconds. 

		if (!WaitNamedPipe(lpszPipename, 20000))
		{
			printf("Could not open pipe: 20 second wait timed out.");
			continue;
		}
	}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值