Работа с памятью [Delphi]

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by darckmilord, 13 Nov 2010.

  1. darckmilord

    darckmilord Elder - Старейшина

    Joined:
    8 Feb 2007
    Messages:
    50
    Likes Received:
    14
    Reputations:
    0
    есть тип

    Code:
    type PMem = ^TMem;
    	TMem = record
    	Addr:Pointer;
    	Size:longword;
    end;
    в процедуре читаю файл в TMemoryStream.

    PHP:
    procedure (var mymemTmem);
    var 
    stmemTMemoryStream;
    begin
      stmem 
    := TMemoryStream.Create;
      
    stmem.LoadFromFile('xxxxxx');

      
    mymem.addr := stmem.memory;
      
    mymem.size := stmem.size;

      
    stmem.free;
    end;
    так вот если выполнять stmem.free то после этого естественно память высвобождаеся и я не могу работать с этой областью по средством

    mymem.addr
    mymem.size

    которые вернулись, а если не выполнять то не будет ли это утечкой. Собственно, как высвободить поток при том, что я мог бы потом работать с загруженным в память файлом по средством указателя и размера данных.
     
  2. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Не использовать TMemoryStream а для загрузки/сохранения структуры объявлять типизированный файл, что-то вроде:
    и процедуры Assign, Writeln, Readln, Eof и т.д.
     
  3. darckmilord

    darckmilord Elder - Старейшина

    Joined:
    8 Feb 2007
    Messages:
    50
    Likes Received:
    14
    Reputations:
    0
    тогда для этого типа придется делать обвязку ибо поток намного проще шифровать и дешифровать. Можно конечно перейти и к блочному шифрованию при считывании, и разжатие/сжатие, а также вырезка части данных из типа когда надо вырезать чисто data данные а хидер файла не читать.

    Слишком геморно, проще копировать область данных перед высвобождением и перемещать, но это тоже не есть гуд когда у нас 30 метров данных в оперативе непонятно зачем скопировали а потом удалили.

    да и mem_file: file of TMem;

    по сколько бит мы читать то будем)) там надо еще динамический массив под данные, собственно идет memGet и в итоге мы получаем если через ООП тот же поток)
     
    #3 darckmilord, 13 Nov 2010
    Last edited: 13 Nov 2010
  4. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    сделай TMem классом, Free будешь вызывать для него
    таким образом решится проблема утечки, и копировать данные не придется
    Насчет якобы ухудшения производительности из-за использования классов даже не думай, тесты показывают ухудшение всего лишь на 20-30% по сравнению с записями

    еще можно TMemoryStream поменять на TFileStream а процедуру оформить в виде функции возвращающей TMem в случае успешной загрузки и nil в случае ошибки.
     
    #4 GhostOnline, 13 Nov 2010
    Last edited: 13 Nov 2010
    1 person likes this.
  5. darckmilord

    darckmilord Elder - Старейшина

    Joined:
    8 Feb 2007
    Messages:
    50
    Likes Received:
    14
    Reputations:
    0
    вообще то TFileStream тоже нужно высвобождать и после его высвобождения будет такая же проблема. TMem классом? зачем? Для данных достаточна указателя и размера в памяти, высвободить их я могу и при помощи MemFree(); Трабла в локальности объекта. т.е. по идее мне нужно залочить изменение переменной в памяти а саму занулить. А создание класса и обработка его дает нам тот же Мемори стрим. проще уж тогда не высвобождать поток совсем а при надобности чистить память через MemFree(); по данным TMem, наверное так и поступлю, в общем то не велика утечка под класс зато нет потери в скорости, а скорость критична.
     
  6. alexey-m

    alexey-m Elder - Старейшина

    Joined:
    15 Jul 2009
    Messages:
    518
    Likes Received:
    100
    Reputations:
    37
    а если мапить файл или не вариант? :rolleyes:
    что-то типа вот такого:
    Code:
    type
      PMem = ^TMem;
      TMem = record
        Addr: Pointer;
        Size: longword;
        hFileMap: THandle;
      end;
    
    procedure Mapping(var mymem: Tmem);
    var
      hFileMap, hFile: THandle;
      Mem: Pointer;
      FileSize: DWORD;
    begin
      hFile:= CreateFileA(PChar('file'), GENERIC_WRITE or GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
      if hFile <> INVALID_HANDLE_VALUE then begin
        FileSize:= GetFileSize(hFile, nil);
        hFileMap:= CreateFileMappingA(hFile, nil, PAGE_READWRITE , 0, FileSize, nil);
        if hFileMap <> INVALID_HANDLE_VALUE then begin
          CloseHandle(hFile);
          Mem:= MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, FileSize);
          if Mem <> nil then begin
            mymem.size:= FileSize;
            mymem.addr:= Mem;
            mymem.hFileMap:= hFileMap;
          end;
        end;
      end;
    end;
    
    procedure FreeTMem(mymem: Tmem);
    begin
      UnmapViewOfFile(mymem.addr);
      CloseHandle(mymem.hFileMap);
    end;
    
    хотя может я что-то не так понял...
     
    #6 alexey-m, 13 Nov 2010
    Last edited: 13 Nov 2010
    1 person likes this.
  7. darckmilord

    darckmilord Elder - Старейшина

    Joined:
    8 Feb 2007
    Messages:
    50
    Likes Received:
    14
    Reputations:
    0
    а чем по идеологии Stream.Free от UnmapViewOfFile отличается?))) нет не вариант. В общем то решил оставить пока как есть и черт с ним...

    еще раз говорю очистку можно сделать и через FreeMem а шифровать/дешифровать и жать данные в потоке удобнее, так что это как бы изобретение колеса)
     
    #7 darckmilord, 13 Nov 2010
    Last edited: 13 Nov 2010
  8. GlooK

    GlooK Elder - Старейшина

    Joined:
    20 Apr 2007
    Messages:
    172
    Likes Received:
    53
    Reputations:
    10
    Ты присваиваешь указатель на память другой переменной, поэтому делать stmem.free не стоит (иначе смысл передавать указатель на память?).
    Вместо этого, по завершению работы с mymem делай команду FreeAndNil(mymem).