2009-07-09 23 views
5

Tôi đã gặp lỗi khó chịu này đã biến mất trong quá khứ nhưng hiện tại sau một thời gian khá lâu nó quay trở lại.FastMM4 nói "Tiêu đề khối đã bị hỏng"

Tôi có hai đối tượng TSam (bắt nguồn từ TPersistent) được tạo và được nạp vào đối tượng TAsmJob (bắt nguồn từ TObjectList).

Khi chạy, biểu mẫu tạo TStringGrid và sau đó AsmJob tạo hai đối tượng SAM đó (và tải một số dữ liệu từ đĩa vào mỗi đối tượng). AsmJob cũng được gán cho lưới. Khi biểu mẫu bị hủy, Grid sẽ xử lý AsmJob bằng cách giải phóng nó, giải phóng các đối tượng TSam. Đây là vấn đề: đối tượng đầu tiên được giải phóng vấn đề withot nhưng cái thứ hai chết khi phương thức kế thừa của nó (trong Destroy destructor) được gọi.

Tôi sử dụng FreeAndNil trong toàn bộ chương trình để giải phóng các đối tượng. Các đối tượng TSam không phải là NIL !!!!! Vì vậy, đây là nỗ lực đầu tiên để giải phóng các đối tượng. Ngay cả dữ liệu bên trong các đối tượng đều nhất quán.

Xương sống của chương trình trông như thế này:

**Create:** 

Form -> StringGrid 
    -> AsmJob -> Sam1, Sam2 
StringGrid.AsmJob:= AsmJob; 


**Free:** 

Form -> StringGrid -> AsmJob -> Sam1, Sam2 

Tôi thực sự không hiểu nơi tôi cố gắng gấp đôi miễn phí hoặc ghi đè lên các đối tượng sau khi nó đã được phát hành.


chỉnh sửa:

Một số lỗi tôi nhận:

  • FastMM đã phát hiện một lỗi trong một khối miễn phí hoạt động quét. FastMM phát hiện thấy một khối đã được sửa đổi sau khi được giải phóng.

  • FastMM đã phát hiện lỗi trong một hoạt động quét khối miễn phí . Tiêu đề khối đã bị hỏng.

Chi tiết:

The current thread ID is 0x19C, and the stack trace (return addresses) leading to this error is: 
402E77 [System][@FreeMem] 
4068DC [System][@DynArrayClear] 
405E2D [System][@FinalizeArray] 
405D31 [System][@FinalizeRecord] 
40432F [System][TObject.CleanupInstance] 
404272 [System][TObject.FreeInstance] 
404641 [System][@ClassDestroy] 
4D313E [UnitSam.pas][TSam.Destroy][297] 
4042BF [System][TObject.Free] 
4149ED [SysUtils][FreeAndNil] 
4D9C0A [UnitAsmJob.pas][UnitAsmJob][TAsmJob.Destroy][180] 

Tôi có tất cả "debug" tùy chọn kích hoạt trong IDE, trong đó có "Phạm vi kiểm tra". Ngoài ra, FastMM4 được đặt ở chế độ gỡ lỗi siêu tích cực. Nếu không có FastMM hoặc bên ngoài trình gỡ rối chương trình chỉ chạy tốt - nhưng tôi biết điều đó không có nghĩa là lỗi không còn ở đó nữa. Trên thực tế nó làm việc (có lẽ) trong hơn một năm, cho đến khi tôi đã cài đặt FastMM.


chỉnh sửa:

Nhờ tất cả mọi người. Không, tôi cảm thấy tôi đang di chuyển một chút theo hướng tốt.

Cấu trúc của chương trình phức tạp hơn Tôi chỉ cung cấp xương sống để giữ cho bài đăng gốc nhỏ. Nhưng những gì heck, nó đã lớn hơn :) Vì vậy, những đối tượng TSam được sử dụng để tải dữ liệu từ đĩa. Một tệp trong mỗi đối tượng. Họ cũng đang làm một số xử lý và xác nhận dữ liệu. Đối với mỗi TSam này tôi cũng có một đối tượng đồ họa hiển thị trên màn hình (đồ họa) dữ liệu chứa trong các đối tượng TSam. Mỗi dòng trong TStringGrid cũng hiển thị dữ liệu trong TSam, nhưng văn bản.

Một câu hỏi tôi có: nếu tôi phá vỡ chương trình thành từng phần nhỏ hơn để tìm ra lỗi, lỗi sẽ vẫn xuất hiện ở đâu? Hoặc chỉ có thể xuất hiện trong cấu hình cụ thể này?


Trả lời "làm thế nào để AsmJob được gán cho TStringGrid để TStringGrid phá hủy AsmJob, bạn có thể chỉ cho chúng tôi không?"

MyGrid = TStringGrid 
    public 
    AsmJob: TAsmJob; 
    end; 

rồi đâu đó trong TForm.Create (dạng chứa Lưới), tôi làm

MyGrid.AsmJob=AsmJob; 

và destructor của MyGrid tôi làm:

begin 
    FreeAndNil(AsmJob); 
    inherited 
end; 

Trả lời

12

Lỗi này có nghĩa là mã của bạn đã bị hỏng cấu trúc của trình quản lý bộ nhớ trong. Ngăn xếp cuộc gọi của bạn đại diện cho điểm, khi MM phát hiện ra điều này. Đây không phải là đường dẫn lỗi hoặc bất kỳ điều gì liên quan đến nó. Lỗi thực sự xảy ra TRƯỚC KHI thời điểm này. Có thể có hoặc không liên quan đến các lớp được đề cập.

You should try to use "Range check errors" option (don't forget to make Build, not Compile) and FastMM in full debug mode (with CheckHeapForCorruption, CatchUseOfFreedInterfaces и DetectMMOperationsAfterUninstall options enabled).

Bạn cũng có thể bật FullDebugModeScanMemoryPoolBeforeEveryOperation biến toàn cầu, để có được một lỗi gần như ngay lập tức sau khi vấn đề xảy ra, nhưng tùy chọn này làm chậm thực hiện của bạn A LOT.

Có lẽ lựa chọn tốt nhất là gọi định kỳ ScanMemoryPoolForCorruptions. Gọi nó ở một nơi. Có lỗi? Gọi nó sớm hơn. Vẫn gặp lỗi? Gọi lại sớm hơn. Không có lỗi? Vấn đề của bạn nằm ở đâu đó giữa những cuộc gọi cuối cùng. Bây giờ bạn có thể sử dụng biến FullDebugModeScanMemoryPoolBeforeEveryOperation để có được vị trí chính xác. Chỉ cần bật nó trên khu vực của mã này và tắt nó ngay sau đó.

Có lỗi rất giống: "FastMM phát hiện thấy một khối đã được sửa đổi sau khi được giải phóng". Trong trường hợp này, mã của bạn sửa đổi cấu trúc bên trong, nhưng bộ nhớ khác, không được sử dụng ở tất cả ("bộ nhớ trống").

BTW, lỗi của bạn KHÔNG phải là hai lần! Nếu đây là một cuộc gọi hai lần, FastMM sẽ cho bạn biết rõ ràng (nó rất dễ phát hiện, vì bạn đang cố gắng giải phóng khối bộ nhớ không được sử dụng hoặc không tồn tại): "Một nỗ lực đã được thực hiện để giải phóng/tái phân bổ một khối chưa phân bổ ".

+0

Cảm ơn Alexander. Tôi không có đầu mối về "ScanMemoryPoolForCorruptions". Tôi đoán là một hàm được cung cấp bởi FastMM DLL. Tôi sẽ đi tìm kiếm về nó ngay bây giờ. – Ampere

+0

Đó là hàm từ tiêu chuẩn FastMM4.pas. Nó là từ phiên bản độc lập hoàn toàn của FastMM. Nó không tồn tại trong phiên bản của FastMM, được tích hợp vào Delphi. Không có DLL được đề cập ở đây. Đây chỉ là một chức năng trong tập tin pas thông thường;) – Alex

+0

Liên kết đáng buồn đã chết. Nhưng bạn có thể truy cập tại: http://web.archive.org/web/20091007162116/http://blog.eurekalog.com/?p=198 – EMBarbosa

4

Một khối tiêu đề bị hỏng thường có nghĩa là một cái gì đó được ghi đè lên bộ nhớ, thường là bằng cách làm một số loại hoạt động không an toàn. Bạn đang sử dụng con trỏ thô hoặc mã lắp ráp trong bất kỳ công việc nào của bạn? Ngoài ra, nếu bạn đã tắt kiểm tra phạm vi và giới hạn, hãy thử bật và xây dựng lại. Họ có thể giúp bắt được rất nhiều loại vấn đề này.

+0

Xin chào Mason. Không có ASM, không có hoạt động con trỏ thô, kiểm tra phạm vi luôn luôn hoạt động. Đây chính xác là những gì tôi đang cố gắng tìm ra cả ngày hôm nay: nơi tôi có thể ghi đè đối tượng chết tiệt đó. – Ampere

+1

Tôi đã nhìn thấy một tình huống như thế này một lần trước đây. Cuối cùng theo dõi nó xuống đến một thư viện bên thứ 3 tôi đã sử dụng mà đã làm một số hoạt động với con trỏ thô và dò dẫm một vài trong số họ. Có thể đó là trường hợp ở đây? –

+0

BTW nó không giống như nó không phải là đối tượng đang được ghi đè, nhưng tiêu đề khối bộ nhớ. Nhưng chỉ để chắc chắn, hãy thử đặt một điểm ngắt trong mã dọn dẹp, nó sẽ cho phép bạn kiểm tra trạng thái của đối tượng này trước khi destructor chạy. Nhìn vào nó trong trình gỡ lỗi và đảm bảo rằng các trường của nó là hợp lệ. (Nếu không, sau đó bạn có thể sử dụng một điểm dừng địa chỉ để làm cho việc tìm kiếm bất cứ điều gì ghi đè lên bộ nhớ của bạn tầm thường.) –

1

Một vài điều và tôi hỏi vì tôi không thể thấy mã của bạn.

Với đoạn mã sau:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    wObjLst : TObjectList; 
begin 
    wObjLst := TObjectList.Create; 
    try 
     wObjlst.OwnsObjects := true; 
     wObjlst.Add(TPersistent.Create); 
     wObjlst.Add(TPersistent.Create); 
    finally 
     freeandnil(wObjlst); 
    end; 
end; 

này làm việc với lỗi ra.

Bạn nói rằng

At runtime, a form creates a TStringGrid and then the AsmJob which creates those two SAM objects (and load some data from disk in each of them). The AsmJob is also assigned to the grid. When the form is destroyed, the Grid takes care of the AsmJob by freeing it, which frees the TSam objects. Here is the problem: the first object is freed withot problems but the second one dies when its inherited method (in Destroy destructor) is called.

câu hỏi đầu tiên của tôi là làm thế nào để AsmJob được giao cho TStringGrid để các TStringGrid phá hủy các AsmJob, bạn có thể chỉ cho chúng ta? Thứ hai, tại sao tạo ra một hậu duệ của TObjectList để làm cho nó lưu trữ hai đối tượng và sau đó giải phóng chúng miễn phí thay vì tự tạo chúng và cho phép TObjectList tiêu diệt chúng như được hiển thị ở trên.

Điều khác cần thử là tải xuống gói FastMM4 đầy đủ từ fastmm.sourceforge.net, cài đặt và sử dụng dll fulldebug để theo dõi chính xác đối tượng nào đang thất bại. Bạn và tôi giả định rằng đó là một trong những đối tượng SAM và nó có thể hoặc có thể không.

+0

Hi Ryan. Ban đầu, ObjectList được đặt thành OwnObj = true, nhưng bây giờ tôi giải phóng các đối tượng "thủ công" để xem lỗi xuất hiện ở đâu. Đây là cách tôi xác định rằng lỗi xuất hiện trong cuộc gọi thừa hưởng (hủy) của các đối tượng TSam. ANYWAY! Nếu tôi tạo và sử dụng các đối tượng TSam mà không cần bằng tay (điều này có nghĩa là không có TAsmJob - đó là một kiểu quản lý của các đối tượng này), mọi thứ hoạt động rất tuyệt vời. Tôi không có lỗi gì cả. -------- PS: Tôi đã có FastMM ở chế độ gỡ lỗi đầy đủ. – Ampere

2

Có thể có một cuộc đua logic ở đâu đó trong mã nơi một đối tượng đang được viết đến khi nó được giải phóng. Thêm NULL-kiểm tra và các cơ chế IPC khác (danh sách khóa vv) để đảm bảo rằng không phải là trường hợp.

Tùy chọn khác có thể là phân lớp mã để thêm nhật ký vào mã đó - và kiểm tra xem các đối tượng có đang được truy cập tuần tự hay không.