Подтвердить что ты не робот

Понимание объема памяти С++ выделяет

Я пытаюсь лучше понять объем памяти, который выделяется в куче в С++. Я написал небольшую тестовую программу, которая в основном делает не что иное, как заполнение ряда 2D-векторов. Я запускаю это на 64-битной виртуальной машине Linux и использую инструмент valgrind massif для профилирования памяти.

В среде, в которой я запускаю этот тест, на: Linux VM работает в VirtualBox на Win10. Конфигурация VM: Базовая память: 5248 МБ, 4CPU, колпачок На 100% дисковый VDI (динамически распределенная память).

Программа тестирования профилей памяти c++:

/**
 * g++ -std=c++11 test.cpp -o test.o
 */

#include <string>
#include <vector>
#include <iostream>

using namespace std;

int main(int argc, char **arg) {
    int n = stoi(arg[1]);
    vector<vector<int> > matrix1(n);
    vector<vector<int> > matrix2(n);
    vector<vector<int> > matrix3(n);
    vector<vector<int> > matrix4(n);
    vector<vector<int> > matrix5(n);
    vector<vector<int> > matrix6(n);
    vector<vector<int> > matrix7(n);
    vector<vector<int> > matrix8(n);

    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) {
            matrix1[i].push_back(j);
        }
    }

    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) {
            matrix2[i].push_back(j);
        }
    }

    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) {
            matrix3[i].push_back(j);
        }
    }

    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) {
            matrix4[i].push_back(j);
        }
    }

    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) {
            matrix5[i].push_back(j);
        }
    }

    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) {
            matrix6[i].push_back(j);
        }
    }

    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) {
            matrix7[i].push_back(j);
        }
    }

    for (int i=0; i<n; ++i) {
        for (int j=0; j<n; ++j) {
            matrix8[i].push_back(j);
        }
    }
}

Я запускаю следующий bash script, чтобы извлечь профили памяти при разных значениях n (test.o - это программа выше, скомпилированная с g++ -std = С++ 11, g++ - версия 5.3 0,0)

valgrind --tool=massif --massif-out-file=massif-n1000.txt ./test.o 250
valgrind --tool=massif --massif-out-file=massif-n1000.txt ./test.o 500
valgrind --tool=massif --massif-out-file=massif-n1000.txt ./test.o 1000
valgrind --tool=massif --massif-out-file=massif-n2000.txt ./test.o 2000
valgrind --tool=massif --massif-out-file=massif-n4000.txt ./test.o 4000
valgrind --tool=massif --massif-out-file=massif-n8000.txt ./test.o 8000
valgrind --tool=massif --massif-out-file=massif-n16000.txt ./test.o 16000
valgrind --tool=massif --massif-out-file=massif-n32000.txt ./test.o 32000

Это дает мне следующие результаты:

|--------------------------------|
| n     | peak heap memory usage |
|-------|------------------------|
| 250   | 2.1 MiB                |         
| 500   | 7.9 MiB                |
| 1000  | 31.2 MiB               |
| 2000  | 124.8 MiB              |
| 4000  | 496.5 MiB              |
| 8000  | 1.9  GiB               |
| 16000 | 6.2 GiB                |
| 32000 | 6.1 GiB                |
|--------------------------------|

Каждая матрица будет размером n ^ 2, у меня всего 8 матриц, поэтому я ожидал, что использование памяти будет около f(n) = 8 * n^2.

Вопрос 1 От n = 250 до n = 8000, почему использование памяти более или менее умножается на 4 при n * = 2?

От n = 16000 до n = 32000 происходит что-то очень странное, потому что valgrind действительно сообщает об уменьшении памяти.

Вопрос 2 Что происходит между n = 16000 и n = 32000, как может быть возможно, что кучная память меньше, а в теории больше данных должно быть выделено?

См. ниже выход массива-визуализатора для n = 16000 и n = 32000.

n = 16000 n = 32000

4b9b3361

Ответ 1

1) Поскольку размеры ваших матричных векторов (и, следовательно, их площадь памяти) растут как n 2 поэтому удвоение n приводит к увеличению объема памяти в четыре раза. Любые отклонения от точной зависимости (в отличие от асимптотики) обусловлены разными факторами (например, метаданные, используемые malloc / std::allocator, метод удвоения размера блока, используемый vector)

2) У вас заканчивается нехватка памяти, поэтому Linux начинает переводить страницы; используйте --pages-as-heap=yes, если вы хотите увидеть общую (активную + выгруженную) память. (Источник: http://valgrind.org/docs/manual/ms-manual.html)