2013-07-15 2 views
0

동적으로 할당 된 주소 공간의 포인터가 스택을 떠나 자마자 자동으로 메모리를 비울 수있는 프로그램을 작성하고 싶습니다. 예제는 다음과 같습니다스택을 떠날 때 자동으로 메모리를 비 웁니다.

procedure FillMemory (var mypointer); 
begin 
    // CopyMemory, Move, etc... with data 
end; 

procedure MyProcedure; 
var 
    MyPointer : Pointer; 
begin 
    MyPointer := VirtualAlloc (NIL, 1024, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); 
    FillMemory (MyPointer); 
    VirtualFree(MyPointer, 0, MEM_RELEASE); // I would like to avoid this... 
end; 

내가 문자열을 사용할 수 있지만, 나 또한 그들을 피하기 위해 같은 것 (I 스택에 문자열 어쨌든 해방받을 경우 너무 잘 모르겠습니다 ...) 어떤 아이디어?

+3

문자열이 스택에 없습니다. 이들은 힙에 대한 참조 카운트 포인터입니다. –

+0

알아요.하지만 어떻게 풀려나나요? –

+2

참조 계산 메커니즘으로 - 일단 0이면 메모리가 해제됩니다. 이것은 문자열 및 동적 배열에 대해 컴파일러에서 관리합니다. 귀하의 질문에 대한 가능한 해결책은 동적 인'바이트 배열 (array of byte) '을 사용하는 것입니다. 나중에 (2009+?) 델파이 버전에서는 TBytes로 미리 정의되어 있습니다 (http://docwiki.embarcadero.com/Libraries/XE4/en/System .SysUtils.TBytes) –

답변

4

내 의견과 아리옥과 논의를 확장하려면

당신이 만약 단지 원시 메모리 블록을 원하면 동적 인 array of byte을 사용하십시오. 컴파일러는 메서드의 마지막에이 메모리를 해제하는 코드를 생성합니다.

type 
    TBytes = array of Byte; // omit for newer Delphi versions 

procedure FillMemory(var Bytes: TBytes); 
begin 
    { passing in here will increase the reference count to 2 } 
    // CopyMemory, Move, etc... with data 
end; // then drop back to 1 

procedure MyProcedure; 
var 
    Buffer : TBytes; 
begin 
    SetLength(Buffer, 1024); // buffer has reference count of 1 
    FillMemory (Buffer); 
end; // reference count will drop to 0, and Delphi will free memory here 

이 모든 것이 의미가 있기를 바랍니다. 자정입니다. 그래서 가장 깨어있는 느낌이 들지 않습니다 ...

+3

+1 이것이 OP가 원했던 것입니다 : 코드가 범위를 벗어 났을 때 자동 릴리스와 함께 원시 메모리의 자동 할당. 참조 카운트에 대해 이야기하는 것이 좋습니다. 그러나 'var'를 사용하면 참조 횟수가 증가하지 않습니다. AFAIK! :)'var'도'const'도 사용하지 않으면 참조 카운트가 증가합니다. 원시 매개 변수뿐입니다. 제발, 제발. 또한 타입 정의를 위해 'TBytes = Byte'라는 배열로 작은 오타를 수정했습니다. –

+1

@ArnaudBouchez가요? 이 질문은'PAGE_EXECUTE_READWRITE'와 함께'VirtualAlloc'을 호출합니다. –

+1

@DavidHeffernan PAGE_EXECUTE_READWRITE를 보지 못했습니다. 그러나 나는 그가 그의 질문에 의심 스러울 때마다 asm 스텁을 생성하는 방법을 알지 못하면 OP가 그것을 필요로하지 않는다고 생각한다. 그는 "RTL을 우회했다"고 썼다.이 경우에는 클래스 기반 접근 방식이 작동하지 않는다. :) –

3

관리되는 유형은 참조가 계산되고 계수가 0으로 떨어지면 완료됩니다. 지역 변수가 있으면 범위를 벗어나면 참조 카운트가 0으로 떨어집니다.

따라서 인터페이스를 사용하여 참조하는 TInterfacedObject의 하위 항목을 만들 수 있습니다. 이런 식으로 뭔가 :

type 
    TLifetimeWatcher = class(TInterfacedObject) 
    private 
    FDestroyProc: TProc; 
    public 
    constructor Create(const DestroyProc: TProc); 
    destructor Destroy; override; 
    end; 

constructor TLifetimeWatcher.Create(const DestroyProc: TProc); 
begin 
    inherited Create; 
    FDestroyProc := DestroyProc; 
end; 

destructor TLifetimeWatcher.Destroy; 
begin 
    if Assigned(FDestroyProc) then 
    FDestroyProc(); 
    inherited; 
end; 

당신은 다음과 같이 사용할 수는 :

LifetimeWatcher이 범위를 잎
procedure MyProcedure; 
var 
    MyPointer: Pointer; 
    LifetimeWatcher: IInterface; 
begin 
    MyPointer := VirtualAlloc (NIL, 1024, MEM_COMMIT or MEM_RESERVE, 
    PAGE_EXECUTE_READWRITE); 
    LifetimeWatcher := TLifetimeWatcher.Create(
    procedure 
    begin 
     VirtualFree(MyPointer, 0, MEM_RELEASE); 
    end; 
) 
    FillMemory(MyPointer); 
end; 

, 당신은 TLifetimeWatcher.Create에 전달 파괴 구현하는 객체와 절차가 실행됩니다.

이 아이디어를 유스 케이스 전용으로 전문화하는 것은 쉽습니다. 그러면 호출 사이트의 코드가 간결 해집니다.

과 같을 것이다

:

function VirtualAllocAutoRelease(Size: SIZE_T; Protect: DWORD; 
    out LifetimeCookie: IInterface): Pointer; 
var 
    Ptr: Pointer; 
begin 
    Ptr := VirtualAlloc(nil, Size, MEM_COMMIT or MEM_RESERVE, Protect); 
    Win32Check(Ptr<>nil); 
    LifetimeCookie := TLifetimeWatcher.Create(
    procedure 
    begin 
     VirtualFree(Ptr, 0, MEM_RELEASE); 
    end 
); 
    Result := Ptr; 
end; 

을 그리고 당신이처럼 사용하십시오 :

procedure MyProcedure; 
var 
    MyPointer: Pointer; 
    LifetimeWatcher: IInterface; 
begin 
    MyPointer := VirtualAllocAutoRelease(1024, PAGE_EXECUTE_READWRITE, 
    LifetimeWatcher); 
    FillMemory(MyPointer); 
end; 
+1

OP는 전체 getmem 프로세스를 우회하려고합니다 (그의 설명 참조). 따라서 수업을 사용하는 것은 불가능합니다. :)이 모든 것은 약간 혼란스러워 보입니다. 그러나 당신의 대답은 완벽합니다 (델파이 델리게이트 대행자 버전을 사용하고 있는지 의심 스럽지만). –

+1

@ArnaudBouchez 질문에있는 어떤 것도 클래스가 실행 가능하지 않음을 나타냅니다. 그의 최근 질문 중 하나는 XE4 태그가 붙어 있지만, 어쨌든 델파이 7에 묶여 있어야하는 이유는 무엇입니까? –

+1

@ArnaudBouchez 비록 내가 실용적인 감각을 볼 수는 없지만, heap manager를 사용하지 않고 일하는 IInterface 구현 클래스를 만들 수는 없을까요? 네, 당신은 오버라이드해야합니다 .NewInstance와 그렇게 하나 - 가능하지만 그렇지 않습니까? 다시 말하지만, 이것에 대한 실질적인 이익에 대해서는 이야기하지 않습니다. 여러분의 "불가능"에 대해서만 말하겠습니다. –

관련 문제