2016-09-20 3 views
4

나는 아래의 프로그램으로 큰 libpacp 파일을 다루고있다.문자열 스트림의 실제 최대 크기를 얻는 방법

문자열 스트림이 OS에서 할당 할 수있는 실제 최대 메모리 크기가 혼란 스럽습니다.

코드의 첫 번째 부분은 libpacp 파일을 처리하는 프로그램입니다.

두 번째 부분은 테스트 용 프로그램입니다.

환경 : Windows 10, VS는 Win32-Released (32 비트) 모드를 준수합니다.

첫 부분 :

#include <fstream> 
#include <iostream> 
#include <sstream> 
#include <string> 
#include <ctime> 
#include <cstdio> 

#define HeaderBytes 24 
#define MaxPkgBytes 65544 //65536+8 
#define KeepDays 7 
#define KeepSeconds (KeepDays*86400) 
#define StartTimeOffset (-1*86400) // -1 day 

using namespace std; 

typedef struct{ 
    int size; 
    char data[MaxPkgBytes]; 
}pkg; 

int catoi(const char* ca){ 
    char tmp[4]; 
    int* iptr; 
    for (int i = 0; i < 4; i++){ 
     tmp[i] = ca[3 - i]; 
    } 
    iptr = reinterpret_cast<int*>(tmp); 
    return *iptr; 
} 

#ifdef _MSC_VER 
#include <windows.h> 
#include <iomanip> 
wstring str2wstr(const std::string& s) 
{ 
    int len; 
    int slength = (int)s.length() + 1; 
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
    wchar_t* buf = new wchar_t[len]; 
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len); 
    wstring wstr(buf); 
    return wstr; 
} 
#endif // _MSC_VER 


int main(int argc, char** argv){ 
    string inFileName, outFileName; 
    stringstream outBuf; 
    fstream fs_in, fs_out; 
    char buf_char; 
    int buf_int, headercount = 0, curPkgIdx= 0, lastPkgIdx = 1, tmp; 
    bool isBroken = false, isValid; 
    clock_t mytime; 
    unsigned int StartTime = 0, PkgTime; 
    pkg buf_pkg[2]; 

    if (argc != 2){ 
     return 1; 
    } 


    inFileName = argv[1]; 
    fs_in.open(inFileName, ios::binary | ios::in); 
    if (!fs_in){ 
     cout << "Can't open the file: " << inFileName << endl; 
     return 1; 
    } 

    outFileName = inFileName; 
    outFileName.insert(outFileName.rfind('.'), "_integrated"); 
    fs_out.open(outFileName, ios::binary | ios::out); 
    if (!fs_out){ 
     cout << "Can't open the file: " << outFileName << endl; 
     return 1;  
    } 


    int invalidPConuter = 0; 
    long long outBufMaxPos = 0; 


    buf_pkg[0].size = 0; 
    buf_pkg[1].size = 0; 

    mytime = clock(); 
    fs_in.read(buf_pkg[curPkgIdx].data, HeaderBytes); 
    outBuf.write(buf_pkg[curPkgIdx].data, HeaderBytes); 
    if (fs_in){ 
     fs_in.read(buf_pkg[curPkgIdx].data, 4); 
     StartTime = catoi(buf_pkg[curPkgIdx].data); 
     StartTime += StartTimeOffset; 
     fs_in.seekg(-4, ios_base::cur); 
    } 
    cout << "start" << endl; 
    while (fs_in.get(buf_char)){ 
     fs_in.seekg(-1, ios_base::cur); 
     if (buf_char == -95){ //0xa1 
      fs_in.read(reinterpret_cast<char*>(&buf_int), sizeof(int)); 
      if (buf_int == 0xd4c3b2a1){ //a1b2 c3d4 
       fs_in.seekg(HeaderBytes-4, ios_base::cur); 
       headercount++; 
      } 
      else fs_in.seekg(-4, ios_base::cur); 
     } 
     else{ 
      fs_in.read(buf_pkg[curPkgIdx].data, 16); 
      PkgTime = catoi(buf_pkg[curPkgIdx].data); 

      /*Set isValid*/ 
      if (PkgTime - StartTime < KeepSeconds) isValid = true; 
      else isValid = false; 

      if (isValid){ //last packetage is valid 
       /*store size of packetage*/ 
       buf_pkg[curPkgIdx].size = catoi(buf_pkg[curPkgIdx].data + 8); 
       /*store size of packetage*/ 
       if (buf_pkg[curPkgIdx].size > MaxPkgBytes) isValid = false; 
      } 
      if (isValid) //Pass packet size check 
      { 
       /*read packetage data*/ 
       fs_in.read(buf_pkg[curPkgIdx].data + 16, buf_pkg[curPkgIdx].size); 
       buf_pkg[curPkgIdx].size += 16; 
       /*read packetage data*/ 

       /*write last packetage data*/ 
       outBuf.write(buf_pkg[lastPkgIdx].data, buf_pkg[lastPkgIdx].size); 
       if (static_cast<long long>(outBuf.tellp()) > outBufMaxPos) 
       { 
        outBufMaxPos = static_cast<long long>(outBuf.tellp()); 
       } 
       else if (static_cast<long long>(outBuf.tellp()) == -1) 
       { 
        cout << "outBufMaxPos: " << outBufMaxPos << endl; 
        system("pause"); 
       } 

       if (outBuf.tellp() >= 0x40000000 - MaxPkgBytes) // 1GB 
       { 
        cout << "write" << endl; 
        fs_out << outBuf.rdbuf(); 
        outBuf.str(""); 
        outBuf.clear(); 
       } 
       /*write last packetage data*/ 

       /*swap idx of buffer*/ 
       tmp = curPkgIdx; 
       curPkgIdx = lastPkgIdx; 
       lastPkgIdx = tmp; 
       /*swap idx of buffer*/ 
      } 
      if (!isValid) 
      { 
       ++invalidPConuter; 
       isBroken = true; 
       fs_in.seekg(-buf_pkg[lastPkgIdx].size - 15, ios_base::cur); 

       /*search correct packetage byte by byte*/ 
       int tmpflag = 0; 

       /*Let PkgTime be invalid. 
       If packet is invalid because of its size, original PkgTime was valid*/ 
       PkgTime = StartTime + KeepSeconds; 

       while (PkgTime - StartTime >= KeepSeconds &&    fs_in.read(buf_pkg[curPkgIdx].data, 4)){ 
        PkgTime = catoi(buf_pkg[curPkgIdx].data); 
        fs_in.seekg(-3, ios_base::cur); 
       } 
       fs_in.seekg(-1, ios_base::cur); 
       /*search correct packetage byte by byte*/ 

       buf_pkg[lastPkgIdx].size = 0; //reset the size of the invalid packetage 
      } 
     } 
    } 
    fs_in.close(); 

    mytime = clock() - mytime; 
    cout << "Repair pacp: " << mytime << " miniseconds." << endl; 
    cout << "Number of deleted headers: " << headercount << endl; 


    mytime = clock(); 

    if (headercount || isBroken){ 
     fs_out << outBuf.rdbuf(); 
     fs_out.close(); 
#ifdef _MSC_VER 
     wstring originFileName, newFileName; 
     originFileName = str2wstr(inFileName); 
     newFileName = str2wstr(inFileName.insert(inFileName.rfind("."), "_origin")); 

     int flag = MoveFileExW(originFileName.c_str(), newFileName.c_str(), 0); 
     if (!flag) 
     { 
      cout << "fail to rename origin file" << endl; 
      cout << showbase // show the 0x prefix 
       << internal // fill between the prefix and the number 
       << setfill('0'); // fill with 0s 
      cout << "Error code: " << hex << setw(4) << GetLastError() << dec << endl; 
     } 
     else 
     { 
      newFileName = originFileName; 
      originFileName = str2wstr(outFileName); 
      flag = MoveFileExW(originFileName.c_str(), newFileName.c_str(), 0); 
      if (!flag) 
      { 
       cout << "fail to rename output file" << endl; 
       cout << showbase // show the 0x prefix 
        << internal // fill between the prefix and the number 
        << setfill('0'); // fill with 0s 
       cout << "Error code: " << hex << setw(4) << GetLastError() << dec << endl; 
      } 
     } 

#endif //_MSC_VER  

    } 
    else 
    { 
     wstring tmpwstr = str2wstr(outFileName); 
     fs_out.close(); 
     if (!DeleteFileW(tmpwstr.c_str())) 
     { 
      cout << "Cannot deleted tmp file (integrated)" << endl; 
     } 
     cout << "The file is completed. Do nothing." << endl; 
    } 

    mytime = clock() - mytime; 
    cout << "Rename file: " << mytime << " miniseconds." << endl; 
    system("pause"); 
    return 0; 

} 

제 부의 의사 코드 :

using namespace std; 

int main(int argc, char** argv){ 
    //leave over the varibles 
    string inFileName, outFileName; 
    fstream fs_out; 
    char buf_char; 
    int buf_int, headercount = 0, curPkgIdx= 0, lastPkgIdx = 1, tmp; 
    bool isBroken = false, isValid; 
    clock_t mytime; 
    unsigned int StartTime = 0, PkgTime; 
    pkg buf_pkg[2]; 
    int invalidPConuter = 0; 
    long long outBufMaxPos = 0; 

    //the varibles will be mentioned 
    fstream fs_in; 
    stringstream outBuf; 

    fs_in.read(Header); 
    outBuf.write(Header); 

    if (fs_in){ 
     StartTime = first_packet_time + StartTimeOffset; 
    } 

    while (!fs_in.eof()){ 
     if (a header read from fs_in){ 
      skip the block of header 
     } 
     else{ 
      fs_in.read(packet header); 

      if (time of packet isValid){ 
       check size of packet 
      } 
      if (size and time isValid) 
      { 
       fs_in.read(packet data); 
       outBuf.write(packet data); 

       if(outBuf out of range) 
       { 
        print(max stringstream size) 
        system("pause"); 
       }    

       if (outBuf size >= 1GB) 
       { 
        write outBuf into output file 
       } 
      } 
      if (size or time isNotValid) 
      { 
       find next valid packet byte by byte 
      } 
     } 
    } 
    fs_in.close(); 

    system("pause"); 
    return 0; 
} 

번째 부분 :

#include <iostream> 
#include <typeinfo> 
#include <sstream> 
#include <string> 

using namespace std; 


#define testsize (80*1024*1024) 
int main() 
{ 
    stringstream ss; 
    char* buf = new char[testsize]; 
    int i = 0; 
    memset(buf, 'a', testsize); 
    while (i < 30) 
    { 
     ss.write(buf, testsize); 
     cout << ss.tellp()/1024/1024 << endl; 
     ++i; 
    } 
    system("pause"); 
} 

에서 첫 번째 부분 인 stringstream의 최대 크기는 약 674MB로 제한됩니다.

그러나 두 번째 부분에서는 stringstream의 최대 크기가 약 2GB로 제한됩니다.

왜 다른가요?

그리고 어떻게 문자열 스트림의 실제 최대 크기를 얻을 수 있습니까?

관련 문제를 검색했지만 대답이 도움이되지 않았습니다.

+2

이유는 64 비트로 전환되지 그리고 당신은 그것에 대해 걱정할 필요가 없습니다? –

+3

전체 코드를 제공해 주시면 귀하의 질문에 대한 이해를 어렵게 만듭니다. 문제와 관련된 짧은 코드를 작성해 주시겠습니까? – WhiZTiM

+1

x86 시스템에서 프로그램을 실행해야 할 수 있습니다. –

답변

1

짧은 대답은 일반적으로 시도하는 것 외에는 알 수 없거나 알 수 없다는 것입니다.

OS에는 단일 메모리 풀이 있습니다. 이 풀은 현재 시스템에서 실행중인 모든 프로세스 (프로세스의 일부가 아닌 장치 드라이버와 같은 몇 가지 사항이 있지만 그 구별은 그다지 중요하지 않습니다)간에 공유됩니다.

일반적으로 풀의 전체 크기는 알 수 없으므로 일반적으로 알 수 없습니다. 디스크가 시스템에 추가/제거 될 때 동적으로 변경 될 수 있습니다.

시스템의 한 프로세스에서 사용할 수있는 풀의 비율은 일반적으로 알 수 없습니다. 다른 프로세스는 일반적으로 메모리를 할당하고 해제하는 시작 및 중지 프로세스이며, 많은 경우 작업 중에도 메모리를 할당하고 해제합니다.

이 모든 것이 동적으로 발생하므로 할당 시도가 잠시 후 성공하고 다음에 실패하고 잠시 후 다시 성공할 수 있습니다. OS가 호출 될 때 사용 가능한 메모리의 양을 알려주는 기능을 제공한다면 (예를 들어), 결과가 호출자에게 반환되기 전에 쉽게 잘못 될 수 있습니다.

일부 제한 사항은입니다. 분명한 사실로 32 비트 프로세스는 4 기가 바이트의 주소 공간만을 가지고 있습니다. 정상적인 방법 (예 : new)을 통해 8 기가 바이트를 할당하려고하면 (예 : new) 성공할 수 없습니다.

N 크기의 단일 할당은 그 어드레스 범위에 연속적인 N 바이트의 범위를 필요로한다. 특히 프로세스가 잠시 동안 실행 된 후에는 (기본 메모리와 독립적 인) 사용 가능한 주소 공간이 조각화되는 경향이 있으므로 사용 가능한 메모리에 관계없이 성공할 수있는 가장 큰 단일 할당은 다음 중 가장 큰 조각의 크기가됩니다. 사용 가능한 주소 공간. 어떤 경우에는

은 "소프트"한계가있다. 예를 들어, Windows 에서 "작업 개체"를 만들고 해당 작업 개체에서 실행중인 프로세스에서 사용하는 최대 메모리를 지정할 수 있습니다. 이렇게하면 실제 RAM을 사용할 수있는 경우에도 할당이 성공하지 못하게 될 수 있습니다.

그래서, 어떤 주어진 순간에, 성공할 수있는 최대 할당이 반 다스 (정도) 다른 요소의 최소이며, 거의 모두는 거의 예측할 수없는 변화에 열려 있습니다. 무엇이 효과가 있는지를 알 수있는 유일한 현실적인 방법은 필요한 것을 할당하고 그것이 성공했는지 확인하는 것입니다. 문제는 윈도우를 참조하기 때문에


1. 여기에서는 Windows를 사용합니다. 메커니즘과 이름은 다양하지만 기본 아이디어는 Windows에서 고유하지 않습니다. 대부분의 다른 OS는 유사한 기능을 제공합니다.

0

차이점은 첫 번째 프로그램의 메모리 공간에 stringstream의 버퍼 외에 다른 것들이있을 가능성이 있습니다. 프로그램이 메모리 블록을 할당하고 해제 할 때 주소 공간은 조각화됩니다. 기가 바이트의 주소 공간이 남아있을 수도 있지만 거대한 버퍼를 저장할 수있는 곳이면 어디에도 단일, 인접한 틈이 없습니다. 또한 메모리가 str2wstr에서 유출됩니다. 당신은 오직 한 번에 메모리의 두 블록을 할당하기 때문에 두 번째 프로그램에서

이 문제가되지 않습니다. 주소 공간이 조각화되지 않으므로 stringstream의 버퍼는 사용 가능한 거의 모든 메모리를 사용할 수 있습니다.

관련 문제