Tôi sử dụng triển khai heap tùy chỉnh trong một trong các dự án của tôi. Nó bao gồm hai phần chính:Heap được tối ưu hóa cho (nhưng không giới hạn) sử dụng đơn luồng
Cố định khối khối kích thước. I E. một đống phân bổ các khối của một kích thước cụ thể mà thôi. Nó phân bổ các khối bộ nhớ lớn hơn (các trang bộ nhớ ảo hoặc từ một vùng nhớ khác), và sau đó chia chúng thành các đơn vị phân bổ nguyên tử.
Nó thực hiện phân bổ/giải phóng nhanh (trong O (1)) và không có phí sử dụng bộ nhớ, không tính đến những điều được áp đặt bởi vùng bên ngoài.
Heap mục đích chung toàn cầu. Nó bao gồm các thùng của đống (kích thước cố định) ở trên. WRT kích thước phân bổ được yêu cầu, nó chọn nhóm thích hợp và thực hiện phân bổ thông qua nó.
Vì toàn bộ ứng dụng là (nhiều) đa luồng - heap toàn cầu khóa xô thích hợp trong khi hoạt động.
Lưu ý: trái ngược với heaps truyền thống, vùng này yêu cầu kích thước phân bổ không chỉ cho phân bổ mà còn cho giải phóng. Điều này cho phép xác định nhóm thích hợp mà không cần tìm kiếm hoặc chi phí bộ nhớ thừa (chẳng hạn như lưu kích thước khối trước khối được phân bổ). Mặc dù hơi kém thuận tiện, điều này là ok trong trường hợp của tôi. Hơn nữa, vì "cấu hình thùng" được biết tại thời gian biên dịch (được thực hiện thông qua mẫu voodoo C++) - nhóm thích hợp được xác định tại thời gian biên dịch.
Cho đến nay mọi thứ đều trông (và hoạt động) tốt.
Gần đây tôi đã làm việc trên một thuật toán thực hiện các hoạt động heap rất nhiều, và tự nhiên bị ảnh hưởng đáng kể bởi hiệu suất heap. Profiling tiết lộ rằng hiệu suất của nó bị ảnh hưởng đáng kể bởi khóa. Nghĩa là, vùng heap hoạt động rất nhanh (phân bổ điển hình chỉ bao gồm một vài hướng dẫn dereferencing), nhưng vì toàn bộ ứng dụng là đa luồng - nhóm thích hợp được bảo vệ bởi phần quan trọng, dựa trên các hướng dẫn liên khóa nặng hơn nhiều.
Tôi đã sửa lỗi này bằng cách đưa thuật toán này vào vùng chuyên dụng của riêng nó, không được bảo vệ bởi một phần quan trọng. Nhưng điều này áp đặt một số vấn đề/hạn chế ở cấp mã. Chẳng hạn như nhu cầu truyền thông tin ngữ cảnh sâu trong ngăn xếp bất cứ nơi nào có thể cần đến heap. Người ta cũng có thể sử dụng TLS để tránh điều này, nhưng điều này có thể gây ra một số vấn đề với việc tái nhập cảnh trong trường hợp cụ thể của tôi.
Điều này làm tôi băn khoăn: Có kỹ thuật nào được biết để tối ưu hóa heap cho (nhưng không giới hạn) sử dụng một luồng không?
EDIT:
Đặc biệt cảm ơn @Voo cho thấy kiểm tra ra tcmalloc của google.
Dường như nó hoạt động tương tự như những gì tôi đã làm nhiều hơn hoặc ít hơn (ít nhất là đối với các đối tượng nhỏ). Nhưng ngoài ra họ giải quyết vấn đề chính xác tôi có, bằng cách duy trì mỗi thread bộ nhớ đệm.
Tôi cũng nghĩ theo hướng này, nhưng tôi đã nghĩ đến việc duy trì mỗi thread heaps. Sau đó giải phóng một khối bộ nhớ được cấp phát từ heap thuộc một thread khác có phần phức tạp: người ta nên chèn nó vào một hàng đợi bị khóa, và thread khác cần được thông báo, và giải phóng phân bổ đang chờ một cách không đồng bộ. Khẳng định không đồng bộ có thể gây ra vấn đề: nếu luồng đó bận vì lý do nào đó (ví dụ thực hiện một phép tính tích cực) - không có sự sắp xếp bộ nhớ thực sự xảy ra. Cộng với kịch bản đa luồng, chi phí của deallocation cao hơn đáng kể.
OTOH ý tưởng với bộ nhớ đệm có vẻ đơn giản hơn nhiều và hiệu quả hơn. Tôi sẽ cố gắng giải quyết nó.
Cảm ơn rất nhiều.
P.S .:
Thật vậy tcmalloc google là tuyệt vời. Tôi tin rằng nó được thực hiện khá giống với những gì tôi đã làm (ít nhất là kích thước cố định một phần).
Tuy nhiên, để trở thành thực tế, có một vấn đề mà vùng heap của tôi vượt trội. Theo tài liệu, tcmalloc áp đặt một chi phí khoảng 1% (tiệm cận), trong khi chi phí của tôi là 0,0061%. Đó là 4/64K chính xác.
:)
Điều này ghi nhớ những thử nghiệm tôi đã thực hiện từ nhiều năm trước. Cơ chế tiêu chuẩn "nghèo" thường được sử dụng chiếm hơn 100 lần so với triển khai "tùy chỉnh" tốt. –
Tôi rất thích xem những gì bạn đã làm nếu nhanh hơn bộ cấp phát bộ nhớ tiêu chuẩn. Như hầu hết các triển khai tiêu chuẩn đã làm những gì bạn yêu cầu làm (và nhiều hơn nữa). Tôi tìm thấy O (1) tuyên bố tò mò đặc biệt là khi bạn yêu cầu bồi thường không có chi phí (Tôi chắc chắn bạn sẽ làm cho một xu khá khi bằng sáng chế của bạn cho rằng đi qua). –
Ý tưởng toàn bộ xô về cơ bản là tcmalloc của google (mặc dù vì đó là một bộ cấp phát chung, nó phải tự động quyết định sử dụng nhóm nào). tcmalloc không sử dụng lưu trữ cục bộ luồng để tránh chính xác vấn đề của bạn và chỉ hiếm khi phân bổ từ vùng lưu trữ chung và do đó tránh khóa. – Voo