2009-08-23 45 views
8

GetMem cho phép bạn phân bổ bộ đệm có kích thước tùy ý. Một nơi nào đó, thông tin kích thước được giữ lại bởi người quản lý bộ nhớ, bởi vì bạn không cần phải nói cho nó biết bộ đệm lớn như thế nào khi bạn chuyển con trỏ tới FreeMem.Làm thế nào tôi có thể tìm thấy kích thước của bộ nhớ được tham chiếu bởi một con trỏ?

Thông tin đó chỉ để sử dụng nội bộ, hoặc có cách nào để lấy kích thước bộ đệm được trỏ tới bởi một con trỏ không?

+0

liên quan: http://stackoverflow.com/questions/969007/is-it-possible-to-get-the-size-of-the-type-that-a-pointer-points-to-in-delphi -7/http://stackoverflow.com/questions/232691/how-can-i-get-the-size-of-an-array-from-a-pointer-in-c –

Trả lời

8

Có vẻ như rằng kích thước của một khối tham chiếu bởi một con trỏ trả về bởi GetMem() phải có sẵn từ một nơi nào, cho rằng FreeMem() không yêu cầu bạn xác định kích thước bộ nhớ cần giải phóng - hệ thống phải có khả năng xác định điều đó, vậy tại sao không phải là nhà phát triển ứng dụng?

Nhưng, như những người khác đã nói, các chi tiết chính xác về quản lý bộ nhớ liên quan KHÔNG được định nghĩa bởi hệ thống ...Delphi luôn có kiến ​​trúc quản lý bộ nhớ thay thế và "giao diện" được định nghĩa cho các trình quản lý bộ nhớ tương thích không yêu cầu chúng cung cấp thông tin này cho một con trỏ tùy ý.

Trình quản lý bộ nhớ mặc định sẽ duy trì thông tin cần thiết theo bất kỳ cách nào phù hợp với nó, nhưng một số trình quản lý bộ nhớ khác gần như chắc chắn sẽ sử dụng một cơ chế hoàn toàn khác, nếu gần như tương tự, vì vậy ngay cả khi bạn hack một giải pháp dựa trên kiến ​​thức thân mật một trình quản lý bộ nhớ, nếu bạn thay đổi trình quản lý bộ nhớ (hoặc nếu nó thay đổi cho bạn, ví dụ như thay đổi trong hệ thống đã định nghĩa, trình quản lý bộ nhớ mà bạn có thể đang sử dụng theo mặc định, như đã xảy ra giữa Delphi 2005 và 2006 chẳng hạn) giải pháp gần như chắc chắn sẽ phá vỡ.

Nói chung, nó không phải là một giả định không hợp lý trên một phần của trình quản lý bộ nhớ RTL/bộ nhớ mà ứng dụng đã biết bộ nhớ lớn như thế nào một con trỏ được phân bổ là GetMem() nó ở nơi đầu tiên! :)

Và nếu ứng dụng của bạn KHÔNG phân bổ con trỏ thì trình quản lý bộ nhớ của ứng dụng của bạn hoàn toàn không biết cách khối tham chiếu có thể lớn đến mức nào. Nó có thể là một con trỏ vào các giữa của một số khối lớn hơn, ví dụ - chỉ nguồn gốc của con trỏ có thể có thể biết làm thế nào nó liên quan đến bộ nhớ nó tham chiếu!

Nhưng, nếu ứng dụng của bạn thực sự không cần phải duy trì thông tin đó về nó riêng con trỏ, sau đó nó có thể tất nhiên dễ dàng đưa ra một phương tiện để đạt được điều này với một lớp singleton đơn giản hoặc thư viện chức năng thông qua đó GetMem()/FreeMem() yêu cầu được định tuyến, để duy trì bản ghi kích thước được yêu cầu liên quan cho mỗi con trỏ được cấp phát hiện tại. Một cơ chế như vậy có thể sau đó tất nhiên dễ dàng phơi bày thông tin này theo yêu cầu, hoàn toàn tin cậy và độc lập với bất kỳ trình quản lý bộ nhớ nào đang được sử dụng.

Đây có thể là tùy chọn duy nhất nếu bản ghi "chính xác" được yêu cầu, vì việc triển khai trình quản lý bộ nhớ nhất định có thể phân bổ khối bộ nhớ lớn hơn cho kích thước dữ liệu nhất định. Tôi không biết liệu có người quản lý bộ nhớ nào thực sự làm điều này không, nhưng nó có thể làm như vậy trong lý thuyết, vì lợi ích hiệu quả.

0

Thông tin đó chỉ để sử dụng nội bộ, hoặc có cách nào để lấy kích thước bộ đệm được trỏ tới bởi một con trỏ không?

Hai "lựa chọn thay thế" có mâu thuẫn lẫn nhau không?

Chỉ sử dụng nội bộ.

+0

Ý tôi là, đó là thông tin bị ẩn khỏi nhà phát triển vì nó chỉ dành cho mục đích sử dụng nội bộ, hoặc có cách nào để lấy nó không? –

+0

Điều gì * I * có nghĩa là ngay cả khi thông tin được sử dụng nội bộ, bạn vẫn có thể có cách để lấy nó. Hoặc có thể không. Câu lệnh đúng là * thông tin này chỉ dành cho sử dụng nội bộ *. Mọi thứ khác không quan trọng. –

0

Có một số thông tin trước khu vực được phân bổ để lưu trữ thông tin meta. Điều này có nghĩa, mỗi khi bạn cấp phát một phần bộ nhớ, một phần lớn hơn sẽ được phân bổ và các byte đầu tiên được sử dụng cho thông tin meta. Con trỏ trả về là khối theo thông tin meta này.

Tôi có thể tưởng tượng rằng định dạng được thay đổi với phiên bản khác của trình quản lý bộ nhớ, do đó, không tính vào điều này.

0

Thông tin đó chỉ dành cho mục đích sử dụng nội bộ. Lưu ý rằng người quản lý bộ nhớ không cần phải lưu trữ kích thước như một phần của bộ nhớ được trả về, nhiều người quản lý bộ nhớ sẽ lưu trữ nó trong một bảng nội bộ và sử dụng địa chỉ bộ nhớ của phần bắt đầu đoạn được đưa ra như một phím tra cứu trong cái bàn đó.

5

Nó dùng để sử dụng nội bộ vì nó phụ thuộc vào MemoryManager được sử dụng. BTW, đó là lý do tại sao bạn cần sử dụng cặp GetMem/FreeMem từ cùng một MemoryManager; không có cách thức kinh điển để biết bộ nhớ đã được bảo lưu như thế nào.
Trong Delphi, nếu bạn nhìn vào FastMM4, bạn có thể thấy rằng bộ nhớ được phân bổ trong các khối nhỏ, trung bình hoặc lớn:
các khối khối nhỏ được phân bổ trong các khối kích thước cố định (kích thước khối được xác định tại hồ bơi) mức trong các loại hình khối)

TSmallBlockType = packed record 
    {True = Block type is locked} 
    BlockTypeLocked: Boolean; 
    {Bitmap indicating which of the first 8 medium block groups contain blocks 
    of a suitable size for a block pool.} 
    AllowedGroupsForBlockPoolBitmap: byte; 
    {The block size for this block type} 
    BlockSize: Word; 

các khối trung cũng được bố trí trong hồ nhưng có một kích thước biến

{Medium block layout: 
    Offset: -8 = Previous Block Size (only if the previous block is free) 
    Offset: -4 = This block size and flags 
    Offset: 0 = User data/Previous Free Block (if this block is free) 
    Offset: 4 = Next Free Block (if this block is free) 
    Offset: BlockSize - 8 = Size of this block (if this block is free) 
    Offset: BlockSize - 4 = Size of the next block and flags 

    {Get the block header} 
    LBlockHeader := PCardinal(Cardinal(APointer) - BlockHeaderSize)^; 
    {Get the medium block size} 
    LBlockSize := LBlockHeader and DropMediumAndLargeFlagsMask; 

các khối lớn được phân bổ riêng với kích thước yêu cầu

TLargeBlockHeader = packed record 
    {Points to the previous and next large blocks. This circular linked 
    list is used to track memory leaks on program shutdown.} 
    PreviousLargeBlockHeader: PLargeBlockHeader; 
    NextLargeBlockHeader: PLargeBlockHeader; 
    {The user allocated size of the Large block} 
    UserAllocatedSize: Cardinal; 
    {The size of this block plus the flags} 
    BlockSizeAndFlags: Cardinal; 
    end; 
+0

Tôi nghĩ rằng ansistring phụ thuộc vào kích thước được tiền tố. Dường như không có cách thống nhất để tải các khối để làm điều này, làm thế nào để làm việc này? Bây giờ có kích thước trong phân bổ không? –

+1

AnsiString có * length * tiền tố, nhưng đó là bởi vì RTL thêm 4 byte thừa trước khi nó gọi 'GetMem'. (Cộng thêm 4 cho số tham chiếu, và như của Delphi 2009, 2 cho trang mã, và 2 cho kích thước phần tử.) Khi bạn kéo dài chuỗi, RTL gọi 'ReallocMem', cho phép trình quản lý bộ nhớ chọn xem để tăng cường phân bổ tại chỗ hoặc phân bổ một khối mới (với một địa chỉ mới). Nó đã được như vậy mãi mãi; AnsiStrings không sử dụng sổ sách kế toán nội bộ của người quản lý bộ nhớ. –

Các vấn đề liên quan