Linux& Windows:使用大文件来保存物理内存

时间:2011-03-09 20:03:21

标签: c++ windows linux

下午好,我们已经实现了一个C ++ cKeyArray类来测试我们是否可以使用Large File API来节省物理内存。在Centos Linux测试期间,我们发现Linux File API与使用堆进行随机访问处理一样快。以下是数字:对于2,700,000行SQL数据库,其中每行的KeySize为62字节,

使用LINUX File API的cKeyArray类 BruteForceComparisons = 197275 BruteForceTimeElapsed = 1,763,504,445微秒 每个BruteForce Comparisons需要两次随机访问,每次随机访问所需的平均时间= 1,763,504,445微秒/(2 * 197275)= 4470微秒

堆,没有cKeyArray类

BruteForceComparisons = 197275 BruteForceTimeElapsed = 1,708,442,690microsecs 每次随机访问所需的平均时间= 4300微秒。

在32位Windows上,数字为,

使用Windows File API的cKeyArray类 BruteForceComparisons = 197275 BruteForceTimeElapsed = 9243787毫秒 每次随机访问的平均时间是23.4毫秒

堆,没有cKeyArray类 BruteForceComparisons = 197275 BruteForceTimeElapsed = 2,141,941毫秒 每次随机访问所需的平均时间为5.4毫秒

我们想知道为什么Linux cKeyArray数字和Linux堆数一样好,而在32位Windows上,平均堆随机访问时间是cKeyArray Windows文件API的4倍。有什么方法可以加快Windows cKeyArray文件API的速度吗?

之前,我们收到了Stack Overflow关于使用Windows内存映射文件API的许多好建议。基于这些Stack Overflow建议,我们实现了一个内存映射文件MRU缓存类,它可以正常运行。

因为我们想要开发一个跨平台的解决方案,我们希望尽职尽责地了解为什么Linux File API如此之快?谢谢。我们试图在下面发布一部分cKeyArray类实现。

#define KEYARRAY_THRESHOLD 100000000   
// Use file instead of memory if requirement is above this number


cKeyArray::cKeyArray(long RecCount_,int KeySize_,int MatchCodeSize_, char* TmpFileName_) {
    RecCount=RecCount_;
    KeySize=KeySize_;
    MatchCodeSize=MatchCodeSize_;
    MemBuffer=0;
    KeyBuffer=0;
    MemFile=0;
    MemFileName[0]='\x0';
    ReturnBuffer=new char[MatchCodeSize + 1];   
    if (RecCount*KeySize<=KEYARRAY_THRESHOLD) {     
        InMemory=true;
        MemBuffer=new char[RecCount*KeySize];
        memset(MemBuffer,0,RecCount*KeySize);
    } else {
        InMemory=false;
        strcpy(MemFileName,TmpFileName_);
        try {
            MemFile=
                              new cFile(MemFileName,cFile::CreateAlways,cFile::ReadWrite);
        }
        catch (cException e)
        {
            throw e;    
        }
        try {
            MemFile->SetFilePointer(
                               (int64_t)(RecCount*KeySize),cFile::FileBegin);
        }
        catch (cException e)
        {
            throw e;    
        }
        if (!(MemFile->SetEndOfFile()))
            throw cException(ERR_FILEOPEN,MemFileName);

        KeyBuffer=new char[KeySize];
    }
}

char *cKeyArray::GetKey(long Record_) {
        memset(ReturnBuffer,0,MatchCodeSize + 1);   
    if (InMemory) {
        memcpy(ReturnBuffer,MemBuffer+Record_*KeySize,MatchCodeSize);
    } else {
        MemFile->SetFilePointer((int64_t)(Record_*KeySize),cFile::FileBegin);
        MemFile->ReadFile(KeyBuffer,KeySize);
        memcpy(ReturnBuffer,KeyBuffer,MatchCodeSize);   
    }
    return ReturnBuffer;
}


uint32_t cKeyArray::GetDupeGroup(long Record_) {
    uint32_t DupeGroup(0);
    if (InMemory) {
         memcpy((char*)&DupeGroup,
                         MemBuffer+Record_*KeySize + MatchCodeSize,sizeof(uint32_t)); 
    } else {
        MemFile->SetFilePointer(
                        (int64_t)(Record_*KeySize + MatchCodeSize) ,cFile::FileBegin);
        MemFile->ReadFile((char*)&DupeGroup,sizeof(uint32_t));
    }
    return DupeGroup;
}

2 个答案:

答案 0 :(得分:5)

在Linux上,操作系统主动将文件数据缓存在主内存中 - 因此,尽管您没有为文件内容明确分配内存,但它们仍然存储在RAM中。这里有一些关于page cache的更多信息的合适链接 - 该描述中只缺少一件事,即大多数Linux文件系统实际上将标准I / O接口实现为页面缓存周围的薄包装器。这意味着,即使您没有显式内存映射文件,系统仍然将其视为封装下的内存映射。这就是为什么你看到两种方法的表现大致相同的原因。

我的第二个建议是将平台特定的东西排除在外,并使用每个平台最快的方法。一定要做基准测试 - 不要对性能做出假设。

答案 1 :(得分:2)

即使在Linux中,您的内存映射解决方案也应该比文件解决方案快10倍。这是我在测试用例中遇到的速度。

每个文件访问系统调用都需要数百个CPU周期才能完成。你的程序可以用来做实际工作的时间。

速度相似的一个原因可能是你以前没有使用过你的记忆图。当第一次访问内存映射页面时,必须将其分配给RAM的物理页面并将其清零,或者如果它是磁盘文件,则必须将其从磁盘加载到RAM中。所有这些都需要相当长的时间。

如果在使用之前触摸(读取或写入值)每个4K的RAM,您应该会看到内存映射中的速度显着增加。