ما هي بيانات مسك الدفاتر التي تحتوي على صفيف ديناميكي دلفي؟
-
19-09-2019 - |
سؤال
إليك برنامج بسيط للتحقق من تخصيص الذاكرة. يوحي التحقق من قبل وبعد القيم مع مدير المهام أن كل صفيف ديناميكية تأخذ 20 بايت من الذاكرة بالحجم = 1. حجم العنصر هو 4، مما يعني 16 بايت من النفقات العامة لبيانات مسك الدفاتر.
من النظر في system.pas، يمكنني العثور على حقل طول الصفيف في -4 بايت، وعدد مرجعي في -8 بايت، ولكن لا يبدو لي أن أجد أي مراجع إلى أخرى 8. أي شخص يعرف ماذا يفعلون؟
نموذج البرنامج:
program Project1;
{$APPTYPE CONSOLE}
type
TDynArray = array of integer;
TLotsOfArrays = array[1..1000000] of TDynArray;
PLotsOfArrays = ^TLotsOfArrays;
procedure allocateArrays;
var
arrays: PLotsOfArrays;
i: integer;
begin
new(arrays);
for I := 1 to 1000000 do
setLength(arrays^[i], 1);
end;
begin
readln;
allocateArrays;
readln;
end.
المحلول
كان لدي نظرة في system.pas كذلك ولاحظت أن استدعاء GetMem في _dynarraycopyrange يدعم تحليلاتك:
حجم مخصص = عدد * حجم العنصر + 2 * Sizeof (Longr ...
. وبعد لذلك ربما الأرقام التي تحصل عليها من إدارة المهام ليست دقيقة للغاية. بامكانك ان تحاول Pointer(someDynArray) := nil
والتحقق من حجم تسرب الذاكرة تقارير Fastmm للحصول على أرقام أكثر موثوقية.
يحرر: فعلت برنامج الاختبار قليلا:
program DynArrayLeak;
{$APPTYPE CONSOLE}
uses
SysUtils;
procedure Test;
var
arr: array of Integer;
i: Integer;
begin
for i := 1 to 6 do
begin
SetLength(arr, i);
Pointer(arr) := nil;
end;
end;
begin
ReportMemoryLeaksOnShutdown := True;
Test;
end.
هذه العوائد
حدث تسرب الذاكرة غير المتوقع. تسرب الكتلة الصغيرة غير المتوقعة هي: 1 - 12 بايت: غير معروف X 1 13 - 20 بايت: غير معروف X 2 21 - 28 بايت: غير معروف X 2 29 - 36 بايت: غير معروف X 1
مما يدعم نظرية العلوية 8 البايت.
نصائح أخرى
مخصصات الذاكرة لها حبيبية لضمان محاذاة جميع المخصصات. هذا هو مجرد الجلاد الناجم عن هذا.
تحديث ... لقد ذهبت فعلا للتحقق من الكود (الذي يجب أن أفعله من قبل) وتوصل إلى نفس الاستنتاج مثل Ulrich، وليس تخزين أي معلومات من النوع، فقط 2 نغمة النطاق النفقات العامة ثم nbelements * عن الإصدادات.
و، مدير المهام غير دقيق لهذا النوع من التدبير.
مع الغرابة أنه إذا قمت بقياس الذاكرة المستخدمة من قبل DynArray، فهي تزيد غير خطية بحجم العنصر: لسجل مع رقم صحيح مع 2 أو 3 أعداد صحيحة، وهو نفس الحجم (20)، مع 4 أو 5 هو 28 ... بعد حبيبات الحاجز.
الذاكرة تقاس مع:
// Return the total Memory used as reported by the Memory Manager
function MemoryUsed: Cardinal;
var
MemMgrState: TMemoryManagerState;
SmallBlockState: TSmallBlockTypeState;
begin
GetMemoryManagerState(MemMgrState);
Result := MemMgrState.TotalAllocatedMediumBlockSize + MemMgrState.TotalAllocatedLargeBlockSize;
for SmallBlockState in MemMgrState.SmallBlockTypeStates do begin
Result := Result + SmallBlockState.UseableBlockSize * SmallBlockState.AllocatedBlockCount;
end;
end;