有人见过调用mlock(2)来防止 STL 容器的内容被交换到磁盘的分配器吗?
编写这样一个分配器只有一个棘手的部分,即通过对要 mlock 的分配进行集群来最小化 mlocked 页的数量。因此,人们可能应该从修改一些共享内存分配器开始?
是否可以将主要分配器之一与现有内存块(池)一起使用?假设我有一个分配的内存块,我想使用 jemalloc 或 tcmalloc 将该块作为自定义堆进行管理。这是可能的还是我必须从头开始编写一个采用这些主要分配器策略之一的分配器?
我有一个类包装了大量的网络数据包字节。该类实现一个队列并提供(除其他外)front()函数,该函数返回构成队列中最旧数据包的字节常量向量。
class Buffer{
unsigned char data[65536];
unsigned int offset;
unsigned int length;
[...]//other fields for maintaining write ptr etc.
public:
const std::vector<unsigned char> front(){
return std::vector<unsigned char>(data + offset, data + offset + length);
}
//other methods for accessing the queue like
//pop(), push(), clean() and so forth...
[...]
}
Run Code Online (Sandbox Code Playgroud)
上述front()函数实现的性能受到从当前数据包占据的范围内不必要的复制字节的影响。由于向量是常量,因此无需复制数据。我想要的是在已经存储在缓冲区中的数据上创建一个向量。当然,向量的析构函数不应该释放内存。
我正在编写一个分配器,其中引用了某个类的另一个实例,该实例跟踪分配的字节数。
下面是我正在尝试做的事情的一个最小示例(从这里改编),只是没有整个内存跟踪类,而是我引用了一些 int 来收集到目前为止分配的字节。这个引用在 main 内部分配,应该传递给 CustomAllocator:
#include <limits> // numeric_limits
#include <iostream>
#include <typeinfo> // typeid
// container
#include <vector>
#include <list>
#include <forward_list>
template<typename T>
class CustomAllocator {
public:
// type definitions
typedef T value_type; /** Element type */
typedef T* pointer; /** Pointer to element */
typedef T& reference; /** Reference to element */
typedef const T* const_pointer; /** Pointer to constant element */
typedef const T& const_reference; /** Reference to constant element */
typedef …Run Code Online (Sandbox Code Playgroud) 和Allocator都可以找到以下关于模板参数的描述(强调我的):std::vectorstd::list
用于获取/释放内存以及构造/销毁该内存中的元素的分配器。该类型必须满足分配器的要求。如果与 不同,则行为未定义
Allocator::value_typeT。
最后一句话对我来说没有意义。如果value_type需要特定的内容,难道不能重新绑定分配器吗?
以下是要点:
1:该项目使用开源存储库NanoRT作为项目中的光线追踪器。
2:本项目在Visual Studio 2019(C++17)下编译
3:该项目编译时带有被视为错误的警告(并且无法更改)。添加定义来抑制这些警告并没有帮助。
然而,看起来此代码的一部分在 C++17 中不起作用,因为它使用了已弃用的内容:(我提供的链接中的第 133 行和第 134 行)
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;
Run Code Online (Sandbox Code Playgroud)
我需要弄清楚如何解决这个问题。该错误建议使用std::allocator_traits,但我真的不熟悉std::allocatoror的这种用法allocator_traits。
查看源代码,这是一个几行修复,还是比这更复杂并且需要重构大部分代码?
看起来pointer被用作 的返回值allocate()和 的第一个参数deallocate(),并size_type以相同的方式使用。
// Actually do the allocation. Use the stack buffer if nobody has used it yet
// and the size requested fits. Otherwise, fall through to the standard
// allocator.
pointer allocate(size_type n, void *hint = 0) {
if …Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一个分配器感知容器。假设我想为三个对象分配一块内存:
T* chunk = std::allocator_traits<Allocator>::allocate(allocator, 3);
Run Code Online (Sandbox Code Playgroud)
(我知道分配器可以有自定义指针类型,因此我应该使用std::allocator_traits<Allocator>::pointer;为了简单起见,我在这里使用原始指针。)
现在我想在索引 2 处创建一个实际对象。我该怎么做?特别是,如何计算指向尚不存在的元素的指针?最明显的选项如下:
std::allocator_traits<Allocator>::construct(allocator, chunk + 2, ...);
Run Code Online (Sandbox Code Playgroud)
不幸的是,chunk + 2似乎并不正确:根据标准,指针运算只能对指向数组元素的指针执行,否则会导致未定义的行为。出于同样的原因,我无法将指针转换为指针std::byte*并对其使用指针算法。(虽然std::allocator定义为在新分配的内存中创建数组,但在 C++20 之前,自定义分配器不存在相同的要求。此外,虽然 C++20 增加了一些“隐式创建对象”的语言,但这并没有申请较早的 C++ 版本。)
那么如何计算要作为第二个参数给出的指针construct而不导致未定义的行为(在 C++20 之前)?
是否可以为struct包含类型作为属性的对象创建分配?
例如
示例结构是
const Content = struct {
content: type,
name: []const u8,
};
Run Code Online (Sandbox Code Playgroud)
然后,我想分配内存,例如2*Content
我知道我可以使用
const list: [2]CustomElement = .{ Content{ .content = Type, .name = "test" }, Content{ .content = Type, .name = "test" } };
Run Code Online (Sandbox Code Playgroud)
但如何使用它们来实现同样的事情allocators呢?
这是行不通的。
comptime {
var list = std.ArrayList(Content).init(test_allocator);
try list.append(Content{ .content = MyType , .name = "test" });
}
Run Code Online (Sandbox Code Playgroud)
我收到错误
error: parameter of type '*std.array_list.ArrayListAligned(Content,null)' must be declared comptime
Run Code Online (Sandbox Code Playgroud)
简而言之
Box是否可以像Rust 中那样构建功能?
我想建立一个由多态对象类型组成的树,Node这些对象是使用自定义 PMR 分配器分配的。
到目前为止,一切都运行良好,但我不知道如何正确删除使用非标准分配器分配的多态对象?我只是想出了一个解决方案来声明一个静态对象,该对象持有对std::pmr::memory_resource.. 的引用,但这很糟糕。有没有“正确”的方法来删除自定义分配的多态对象?
这是一个独立的示例:
#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <functional>
#include <memory_resource>
struct Node {
// NOTE: this is actually not necessary..
using allocator_type = std::pmr::polymorphic_allocator<Node>;
void operator delete(void *ptr, std::size_t sz) noexcept {
Node::deleter(ptr, sz);
}
// don't bother with getters/setters so far..
std::pmr::string name;
template <class TNode >
static TNode *create(std::string_view name, std::pmr::memory_resource *res) {
std::pmr::polymorphic_allocator<TNode> alloc(res);
auto ptr = alloc.allocate(1);
::new (ptr) TNode(alloc);
ptr->name = …Run Code Online (Sandbox Code Playgroud) 假设我们想要将n数据字节从void* src复制到void* dst。众所周知,标准库的实现经过memcpy严格优化,可以使用依赖于平台的向量化指令和各种其他技巧来尽可能快地执行复制。
现在假设p后面的数据字节src + n是可读的并且p后面的数据字节dst + n是可写的。另外,假设在 中写入任意垃圾也是可以的[dst + n, dst + n + p)。
显然,这些假设扩大了我们可能采取的行动的范围,可能导致更快的 memcpy。例如,我们可以在少量未对齐的 128 位指令(加载 + 存储)中复制少于 16 个尾随字节的某些部分。也许这种额外的假设还允许使用其他技巧。
01234 ..... n
src: abcdabcdabcdabcdabcdabcGARBAGEGA
v v
dst: ______(actl dst)________(wrtbl)_
| block1 || block2 |
Run Code Online (Sandbox Code Playgroud)
请注意,当您需要在分配的容量足以容纳p+ 总字符串大小字节的缓冲区内附加字符串序列时,这些假设实际上相当实用。例如,以下例程可能发生在数据库内部的某个位置:
给你一个二进制字符串
char* dictionary和一个整数数组int* offsets,它是字典中偏移量的单调序列;这两个变量表示从磁盘获取的字符串字典。您还有一个整数数组,int* indices指示必须将字典字符串写入输出缓冲区的顺序char* buffer。
使用上述技术,您可以安全地编写每个新字符串,而不关心其右侧的垃圾,因为它将被要附加的下一个字符串覆盖。
问题是: