【问题标题】:What is the rationale behind std::allocator::max_size()?std::allocator::max_size() 背后的基本原理是什么?
【发布时间】:2014-03-04 21:13:50
【问题描述】:

我知道max_size() 来自std::allocator 是一个理论上的限制,但我只是尝试了一些东西,我得到的数字非常巨大;那么我应该如何解释这个数字以及这个函数背后的理念是什么?

我的例子:

#include <iostream>
#include <memory>
#include <cstdint>
typedef int8_t Tnum_1;
struct X
{
    template <typename T>
    static void printAllocInfo()
    {
        std::cout << std::allocator<T>().max_size() << "\t Alloc max_size\n";
        std::cout << ((std::allocator<T>().max_size()) / (1024))
                  << "\t Alloc max_size / 1024\n";
        std::cout << (((std::allocator<T>().max_size()) / (1024)) / (1024))
                  << "\t\t Alloc max_size / 1024 / 1024\n";
    }
};
int main()
{
    X::printAllocInfo<Tnum_1>();
    return (0);
}

打印出来:

18446744073709551615     Alloc max_size
18014398509481983        Alloc max_size / 1024
17592186044415           Alloc max_size / 1024 / 1024

考虑到我只是使用int8_t 作为模板参数,这意味着我可以在我的机器上分配18446744073709551615 bytes 吗?这个数字太大了,以至于它开始失去任何实际意义。

【问题讨论】:

    标签: c++ memory-management c++11


    【解决方案1】:

    您引用的那个数字当然是 2^64 -1,也就是可以表示的最大 64 位无符号整数。所有max_size() 表示它不支持任何更大的东西,而不是它支持低于该大小的所有东西。

    这取决于您的操作系统是否将其实际提供给您的程序。但是,由于您可以在运行程序的不同机器上编译程序(包括遥远未来的机器),因此没有理由将 max_size() 限制为较小的数字。

    注意:如果您阅读 C++ 标准中的 表 31 — 分配器要求,您会发现 a 类型为 X 的分配器对象如下:

    a.allocate(n):为n 类型为T 的对象分配了内存,但是 不构造对象。

    a.max_size():可以有意义地传递给的最大值 X::allocate()

    所以max_size 是可以分配的最大对象数,而不是字节数。

    【讨论】:

    • 也许我之前的问题不是很清楚,让我重新表述一下:谁使用max_size 以及为了什么?
    • @user2485710 这只是为了不破坏在其编译的较大硬件上运行的程序。 64 位现在看起来很离谱,但 640K 曾经对每个人来说都足够了。如果底层整数可以支持 2^64,则根本没有理由将 max_size 限制为当前的硬件级别。
    • 我真的不明白,我真的不明白为什么 C++ 标准还要费心提供这样的功能,这个 2^64 是一个架构限制,它甚至不依赖于实现或到图书馆,它只是告诉我我基本上有一台 64 位机器(甚至不是以最清晰的方式,也许他们可以简单地提供一个基数和一个指数,这会更容易阅读)。我明白了,但我不明白这个信息可能起到什么作用。
    • 好吧,它告诉你你不在一个 32 位系统上,不可能分配超过 4GB。
    • @user2485710 在 16 位或 32 位系统上,这些限制实际上将绑定到某些分配,因此 max_size 在那里很有用。谁知道2050年一些巨大的分布式数据中心实际上可以分配2^64字节。
    【解决方案2】:

    之前提供的答案不完整,因为它们只提到字节数,而不是对象数。

    documentation for max_size 表示函数应该返回“理论上可能的最大 n 值,为此调用 allocate(n, 0) 可以成功”,其中 n 是对象的数量。它还说对于某些分配器实现它应该返回

    std::numeric_limits<size_type>::max() / sizeof(value_type)
    

    而不是

    std::numeric_limits<size_type>::max()
    

    STL 容器(例如 - std::vectorstd::mapstd::list)使用 max_size 根据对象计数而不是字节计数来计算容器大小。因此,max_size() 不应该返回操作系统上可用的字节数,而是使用可用字节数来计算分配器可以容纳的对象数

    如果您为 STL 容器编写了分配器类,则可以像这样实现 max_size() 函数来提供准确的对象计数,而不是使用 std::numeric_limits&lt;size_type&gt;::max() 进行高估。

    size_type max_size() const
    {
        const unsigned long long bytesAvailable = GetTotalAvailableMemory();
        const unsigned long long maxPossibleObjects = bytesAvailable / sizeof(value_type);
        return maxPossibleObjects;
    }
    

    您可以根据您的操作系统实现GetTotalAvailableMemory() 之类的功能。两者都将返回程序进程可能使用的未分配字节数。

    #if defined(unix) || defined(__unix__) || defined(__unix)
    
    #include <unistd.h>
    
    unsigned long long GetTotalAvailableMemory()
    {
        const long pageCount = sysconf( _SC_PHYS_PAGES );
        const long pageSize = sysconf( _SC_PAGE_SIZE );
        const unsigned long long totalBytes = pageCount * pageSize;
        return totalBytes;
    }
    
    #endif
    
    #if defined(_WIN64) || defined(_WIN64)
    
    #include <windows.h>
    
    unsigned long long GetTotalAvailableMemory()
    {
        MEMORYSTATUSEX status;
        status.dwLength = sizeof( status );
        GlobalMemoryStatusEx( &status );
        return status.ullAvailVirtual;
    }
    
    #endif
    

    【讨论】:

      【解决方案3】:

      来自http://www.cplusplus.com/reference/vector/vector/max_size/

      由于已知的系统或库实现限制,这是容器可以达到的最大潜在大小,但绝不保证容器能够达到该大小:在此之前的任何时候它仍然可能无法分配存储已达到大小。

      正如 TemplateRex 指出的那样,您看到的数字是 2^64。基本上,这告诉你一个基于软件编写方式的理论限制,而不是操作系统真的会接受如此巨大的分配。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-18
        • 2017-03-09
        • 1970-01-01
        • 2010-12-09
        • 2012-05-18
        • 1970-01-01
        相关资源
        最近更新 更多