2009-12-10 9 views
10

मैं डेस्कटॉप सिस्टम के लिए लक्षित एक एप्लिकेशन विकसित कर रहा हूं जिसमें 256 एमबी रैम (विंडोज 2000 और ऊपर) के रूप में कम हो सकता है। मेरे आवेदन में मेरे पास यह बड़ी फ़ाइल है (> 256 एमबी) जिसमें लगभग 160 बाइट/प्रत्येक के निश्चित रिकॉर्ड हैं। इस एप्लिकेशन की एक लंबी प्रक्रिया है जिसमें समय के साथ, यह यादृच्छिक रूप से फ़ाइल का लगभग 9 0% (पढ़ने और लिखने के लिए) तक पहुंच जाएगा। किसी भी रिकॉर्ड रिकॉर्ड को उस विशेष रिकॉर्ड के पढ़ने से 1,000 से अधिक रिकॉर्ड एक्सेस नहीं होंगे (मैं इस मान को ट्यून कर सकता हूं)।CreateFileMapping, MapViewOfFile, सिस्टम मेमोरी को पकड़ने से कैसे बचें

मेरे पास इस प्रक्रिया के लिए दो स्पष्ट विकल्प हैं: नियमित I/O (FileRead, FileWrite) और मेमोरी मैपिंग (CreateFileMapping, MapViewOfFile)। उत्तरार्द्ध पर्याप्त स्मृति वाले सिस्टम में अधिक कुशल होना चाहिए, लेकिन कम स्मृति वाले सिस्टम में यह अन्य अनुप्रयोगों की स्मृति को स्वैप कर देगा, जो मेरे आवेदन में नो-नो है। क्या प्रक्रिया को सभी मेमोरी खाने से रोकने का कोई तरीका है (उदाहरण के लिए, मेमोरी पेजों की फ्लशिंग को मजबूर करना जैसे मैं अब तक नहीं पहुंच रहा हूं)? यदि यह संभव नहीं है, तो मुझे नियमित I/O पर वापस जाना चाहिए; मुझे लेखन भाग के लिए ओवरलैप I/O का उपयोग करना पसंद होता था (क्योंकि पहुंच इतनी यादृच्छिक है), लेकिन प्रलेखन writes of less than 64K are always served synchronously कहता है।

I/O में सुधार के लिए कोई भी विचार स्वागत है।

+0

से ProcessExplorer का उपयोग करें शायद वर्चुअलफ्री (MEM_DECOMMIT) मदद की जा सकती है? मैं इसके साथ परिचित नहीं हूँ। –

+1

नहीं, वर्चुअलफ्री (MEM_DECOMMIT) एमएमएफ के लिए विफल रहता है; मैंने अभी जाँच की। –

उत्तर

10

अंततः मुझे here धागे से निकाला गया रास्ता मिला। चाल उन श्रेणियों पर VirtualUnlock() का उपयोग कर रही है जिन्हें मुझे असामान्य करने की आवश्यकता है; हालांकि यह फ़ंक्शन त्रुटि 0x9e ("सेगमेंट पहले से अनलॉक है") के साथ FALSE लौटाता है, स्मृति वास्तव में जारी की जाती है, भले ही पृष्ठों को संशोधित किया गया हो (फ़ाइल सही ढंग से अपडेट की गई हो)।

#include "stdafx.h" 

void getenter(void) 
{ 
    int  ch; 
    for(;;) 
    { 
     ch = getch(); 
     if(ch == '\n' || ch == '\r') return; 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    char* fname = "c:\\temp\\MMFTest\\TestFile.rar";  // 54 MB 
    HANDLE hfile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); 
    if(hfile == INVALID_HANDLE_VALUE) 
    { 
     fprintf(stderr, "CreateFile() error 0x%08x\n", GetLastError()); 
     getenter(); 
     return 1; 
    } 

    HANDLE map_handle = CreateFileMapping(hfile, NULL, PAGE_READWRITE | SEC_RESERVE, 0, 0, 0); 
    if(map_handle == NULL) 
    { 
     fprintf(stderr, "CreateFileMapping() error 0x%08x\n", GetLastError()); 
     getenter(); 
     CloseHandle(hfile); 
     return 1; 
    } 

    char* map_ptr = (char*) MapViewOfFile(map_handle, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0); 
    if(map_ptr == NULL) 
    { 
     fprintf(stderr, "MapViewOfFile() error 0x%08x\n", GetLastError()); 
     getenter(); 
     CloseHandle(map_handle); 
     CloseHandle(hfile); 
     return 1; 
    } 

    // Memory usage here is 704KB 
    printf("Mapped.\n"); getenter(); 

    for(int n = 0 ; n < 10000 ; n++) 
    { 
     map_ptr[n*4096]++; 
    } 

    // Memory usage here is ~40MB 
    printf("Used.\n"); getenter(); 

    if(!VirtualUnlock(map_ptr, 5000 * 4096)) 
    { 
     // Memory usage here is ~20MB 
     // 20MB already freed! 
     fprintf(stderr, "VirtualUnlock() error 0x%08x\n", GetLastError()); 
     getenter(); 
     UnmapViewOfFile(map_ptr); 
     CloseHandle(map_handle); 
     CloseHandle(hfile); 
     return 1; 
    } 

    // Code never reached 
    printf("VirtualUnlock() executed.\n"); getenter(); 

    UnmapViewOfFile(map_ptr); 
    CloseHandle(map_handle); 
    CloseHandle(hfile); 

    printf("Unmapped and closed.\n"); getenter(); 

    return 0; 
} 

आप देख सकते हैं, इस कार्यक्रम की वर्किंग सेट को क्रियान्वित करने VirtualUnlock(), बस के रूप में मैं जरूरत के बाद कम हो जाता है:

यहाँ मेरी नमूना परीक्षण कार्यक्रम है। उचित रूप से अनलॉक करने के लिए मुझे केवल उन पृष्ठों का ट्रैक रखने की आवश्यकता है जिन्हें मैं बदलता हूं।

+0

ग्रेट, इसे साझा करने के लिए धन्यवाद। मैं मेमोरी मैप की गई फाइलों द्वारा उपयोग की जाने वाली मेमोरी की मात्रा को नियंत्रित करने के तरीके के लिए सख्त रूप से देख रहा था, और मैं उम्मीद कर रहा था कि यह पहले ही खो रहा है। मुझे उम्मीद है कि एमएस अक्षम नहीं होगा यह कुछ भविष्य ओएस है। आखिरकार, हम वांछित पृष्ठों को केवल प्रतिबद्ध और निष्कासित क्यों नहीं कर सकते? – Suma

+0

नोट: आपके द्वारा वर्णित त्रुटि कोड वर्चुअल अनलॉक दस्तावेज़ टिप्पणी के आधार पर अपेक्षित प्रतीत होता है: "यदि निर्दिष्ट सीमा में से किसी भी पृष्ठ को लॉक नहीं किया गया है, तो वर्चुअल अनलॉक वर्किंग सेट से ऐसे पृष्ठों को हटा देता है, पिछली त्रुटि ERROR_NOT_LOCKED पर सेट करता है, और गलत लौटाता है। " – Suma

+0

एक और नोट: प्रयोग कुछ हद तक भ्रामक है। प्रक्रिया का कामकाजी सेट कम हो गया है, लेकिन इसका मतलब यह नहीं है कि पृष्ठ को त्याग दिया गया है। यदि आप फिर से मानचित्र करेंगे, तो आप देख सकते हैं कि आप इसे तुरंत प्राप्त कर सकते हैं, बिना किसी पृष्ठ फ़ाइल गतिविधि के। Http://stackoverflow.com/questions/3525202/how-can-i-decommit-a-file-mapped-page/3525266#3525266 में मेरा प्रयोग देखें – Suma

1

क्या आप पूरी फ़ाइल को MapViewOfFile के साथ एक ब्लॉक के रूप में मैप कर रहे हैं? यदि आप हैं, तो छोटे भागों को मैप करने का प्रयास करें। आप FlushViewOfFile()

+0

मैं अनुक्रमिक रूप से फ़ाइल तक नहीं पहुंचता; एक यादृच्छिक पैटर्न है जिसे मैं फ़ाइल तक पहुंचने के लिए नियंत्रित नहीं कर सकता, इसलिए इसके छोटे हिस्सों को मैप करना बहुत ही निष्क्रिय होगा। इसके अलावा, FlushViewOfFile() किसी भी स्मृति को मुक्त नहीं करता है; केवल गंदे पृष्ठों के लेखन को मजबूर करता है। –

3

के साथ एक दृश्य को फ्लश कर सकते हैं बस पूरी फ़ाइल को स्मृति में मैप करें। यह आभासी उपभोग करता है लेकिन शारीरिक स्मृति नहीं। फ़ाइल को डिस्क से टुकड़े से पढ़ा जाता है और उसी नीतियों द्वारा स्मृति से निकाल दिया जाता है जो स्वैप फ़ाइल को नियंत्रित करता है।

+4

ठीक है, यह ठीक है समस्या है। स्वैप फ़ाइल को नियंत्रित करने वाली नीतियां फ़ाइल कैश की तुलना में सामग्री को स्मृति में अधिक रखती हैं, इसलिए मैप किए गए फ़ाइल तक पहुंचने से अंततः अन्य प्रक्रियाओं में से अधिकांश स्वैप हो जाएंगे। –

2

वर्चुअल अनलॉक काम नहीं करता है। आपको क्या करना है FlmViewOfFile (map_ptr, 0) को UnmapViewOfFile (map_ptr) से पहले कॉल करें। विंडोज टास्क मैनेजर भौतिक स्मृति उपयोग नहीं दिखाएगा। SysInternals

संबंधित मुद्दे