From YYpBD's MediaWiki
TList를 사용시 메모리 절약하는 한가지 방법..........
TList는 이름그대로 리스트를 구현해놓은 클래스이다....
이런저런 용도로 참 많이도 사용하게 되는데....
우선 이넘이 어케 구현되어있는가를 보자.....
이넘은 내부적으로 리스트를 구현하기 위해서 포인터 배열을 사용한다..
그 배열의 길이는 자그마치...
2147483647 div 16
즉, 134217727까지 다시한번 말하면....
PointerList = array[0..134217727 - 1] of Pointer;
이렇게 되어있다....
실제로 소스코드에 저런 배열을 하나 선언하면.....
아마도 하드를 엄청 긁어댈것이다.... 메모리 스와핑하느라고...
그런데 TList는 저것을 다시 포인터형으로 사용한다.....
즉, 정적인 배열로 사용하는것이 아니라 필요할때 메모리크기를 확보해서 사용한다....
TList.Create; 할때에는 배열의 크기를 잡지 않으므로..
Create하고나면 그다지 메모리에 큰변화가 없다..
아이템을 추가할때 일정한 룰에 의해서 ReallocMem를 이용해서 그 배열의 길이를 점점 늘려간다....
TList의 protected에는 Grow;라는 메소드가 있는데....
procedure TList.Grow;
var
Delta: Integer;
begin
if FCapacity > 64 then
Delta := FCapacity div 4
else
if FCapacity > 8 then
Delta := 16
else
Delta := 4;
SetCapacity(FCapacity + Delta);
end;
요렇게되어있다...
아이템이 하나늘어날때마다 포인터 배열의 길이를 하나씩 늘리는것이아니라..
아이템을 추가하기전 현재 카운트와 포인터배열의 길이가 같으면 배열의 길이를 늘리는데..
현재 Count가 64개 이상이면 Count div 4 만큼씩 크기를 늘리고..
현재 Count가 64개 이하일때 8보다는 크면 16을 더 늘리고 8보다 작으면 4를 늘린다..
Grow; 메소드는 SetCapacity 메소드를 호출하고 있는데 SetCapacity 메소드가 ReallocMem을 이용해서 실제 포인터 배열의 크기를 다시 세팅한다....
자.....
문제는 Count가 줄어들었을때이다....
Count가 늘어날때는 당연히 메모리를 점점 많이 먹어야하는게 정상이지만....
Count가 팍팍 줄어들어도.... 포인터 배열의 길이는 줄지 않는다....
그러므로 순간적으로 왕창 늘렸다가... 팍 줄이는 경우.....
순간적으로 사용한 포인터 배열의 길이가 줄어들지는 않는다......
그러므로 그런 현상이 많아지면 메모리가 낭비된다....
실제로 TList를 사용하면서 메모리를 많이 잡아먹는 경우가 여기에 해당되는 경우가 많다.....
자...
그럼 해결책을 찾아보자.....
Count가 아예 0으로 될경우에는 반드시 Clear; 를 하자....
물론
for i := List.Count - 1 downto 0 do
begin
//아이템삭제
//List.Delete( i );
end;
이렇게 해도 실제 데이터가 삭제되기는 마찬가지지만..
이렇게 하면 포인터배열의 길이는 줄지 않는다....... 데이터만 제거할뿐이다....
Clear메소드를 보면...
procedure TList.Clear;
begin
SetCount(0);
SetCapacity(0);
end;
이렇게 되어있다.... 갯수를 0으로 세팅하고...포인터배열의 길이를 0으로 세팅한다는것을 알수 있다.....
그럼...
Count가 0이 되지않고 남아있는 경우는?
당연히 SetCapacity 메소드를 호출해서 수동으로 포인터배열의 길이를 줄일수 있다....
그런데 SetCapacity 메소드가 protected 에 선언되어져 있으므로
TList를 상속받는경우는 별 문제없겠지만...
직접 사용하는 경우는
type AList=class(TList);
...
AList( List1 ).SetCapacity( ..
이런 방법으로 사용할수 있을것이다......
........
포인터배열의 길이를 자꾸 늘렸다 줄였다하면 오히려 더 비효율적일수 있으므로...
시기 적절하게 사용하면 TList로 인한 메모리 낭비를 많이 줄일수 있을것이다.....
그리고... 단순히 메모리만의 문제가 아니라....메모리 사용량이 많아지면 하드스와핑도 많아지므로 하드를 긁어대는 경우도 많아지게되므로 .. 결국 전체적으로 버벅거리는 현상도 많아지게된다...
그러므로 TList를 사용할때 Count변화가 심한 경우나 혹은 TList를 많이 사용하는 경우에 적절히 사용하면 매우 효과적일것이다....
쩝.......