Динамическое выделение памяти для улучшения производительности c ++

0

Доброй ночи

Я изучаю C++ для разработки научного кода. В отличие от моей стратегии обучения, используемой в python и MATLAB, я пытаюсь изучить C++ старым и глубоким способом (используя книгу ref [1]). Я изо всех сил пытаюсь понять указатели и динамическое распределение памяти.

Я наткнулся на это упражнение, и появились некоторые сомнения. Упражнение представляет собой простое умножение матрицы 2x2. Код:

#include<iostream>
//Perform C[2][2] = A[2][2]*B[2][2] Using dynamic memory allocation 

int main(){

    //declaring length of the matrices
    int row,col;
    row = 2;
    col = 2;

    //Allocating memory for matrice A [heap ?]
    double** A, **B, **C;
    A = new double* [row];
    B = new double* [row];
    C = new double* [row];
    for (int i=0; i<row; ++i){
        A[i] = new double [col];
        B[i] = new double [col];
        C[i] = new double [col];
    }

    //Performing calculation
    for (int i=0; i<2; ++i){
        for (int j=0; j<2; ++j){
            A[i][j] += 10;
            B[i][j] += 20;
            C[i][j] += A[i][j]*B[i][j];
            std::cout << C[i][j] << " ";
        }
        std::cout << std::endl;
    }

    //Deleting memory allocation [Is there an memory leak ? (No *=NULL)]
    for (int i=0; i<2; ++i){
        delete[] A[i];
        delete[] B[i];
        delete[] C[i];
    }
    delete[] A;
    delete[] B;
    delete[] C;

    return 0;
}

Мои сомнения:
1 - Я читал о разделении памяти (global/stack/heap), где они находятся в аппаратном обеспечении? Кэш HD/RAM/CPU?

2 - когда я выделяю массив:

int arrayS[2];       //Is this at the stack ?

int* arrayH;         //Is this at the heap ?
arrayH = new int [2];

3 - В моем решении матричной задачи. Есть ли утечка памяти или создание мусора? (обратите внимание, что я не указывал массивы на * = NULL, чтобы избавиться от адреса)

4 - Вы предлагаете какой-либо способ повысить эффективность и эффективность моего кода?

Спасибо !

  • 3
    Это действительно плохой пример кода. Использование сырых указателей в качестве массивов легко приводит к ошибкам; правильный класс, инкапсулирующий концепцию массива, поддерживаемый std::vector будет намного легче понять правильно и намного легче правильно использовать повторно. И при достаточной оптимизации компилятора он не будет работать хуже.
  • 0
    Как минимум, используйте std::unique_ptr чтобы сохранить вашу память.
Показать ещё 1 комментарий
Теги:
memory
allocation

3 ответа

1

В c++ объект может быть расположен в стеке и в куче. В вашем примере int arrayS [2] находится в стеке funcion, в котором он был объявлен. Если вы хотите создать объект в куче (доступная память ко всем функциям, которые существуют в программе), вы должны использовать оператор new. Указатель, который хранит адрес выделенного объекта (в вашем случае arrayH), также нажимает на стек функции, в которой он объявлен. На самом деле память один процесс (исполняемая программа) погружается в три части:

  • Область кода (область, в которой находится код программы);

  • Область стека (начинается в месте, где указатель Stack-Pointer указывает на память. Указатель стека - это регистр, который хранит каждый раз адрес текущего стека. В программе больше одного стека за один раз это зависит от уровня рекурсивности вашей программы)

  • Область данных (это глобальная память, доступная из всей программы. Она выделена в c++ только с помощью нового оператора или глобальной переменной)

  • Он существует также shared_memory, который позволяет программисту выделять память, доступную более чем в одном процессе.

    ** В вашем коде отсутствует утечка памяти. Но в c++ реализована концепция smart_pointer, которая очень похожа на габаб-колектор из С# и Java **

    Также c++ является языком программирования ООП, поэтому вы обязательно должны писать свой код, используя классы, наследование, полиморфизм и т.д.

  • 0
    «Если вы хотите создать объект в куче ... вы должны использовать оператор new» - Технически это не так ... у нас есть, например, std::make_shared . (Конечно, под капотом, вероятно, будет использоваться operator new .)
  • 0
    определенно использует оператор new или даже функцию c malloc
1

Я читал о разделении памяти (global/stack/heap), где они находятся в аппаратном обеспечении? Кэш HD/RAM/CPU?

Они могут быть сохранены везде, где ваша программа C++ решит, что они должны быть. Некоторые локальные переменные, вероятно, существуют только в регистрах, если они имеют короткий срок службы и никогда не имеют указателя на них.

Вероятность того, что все остальное произойдет где-то в системной ОЗУ (которая может быть выгружена на диск, если ваш процесс несчастлив). Разница в том, как они используются программой, а не там, где они есть. Где они являются деталью реализации, о которой вам действительно не нужно беспокоиться.

когда я выделяю массив

Да, ваш анализ стека против кучи правильный. Ваш первый (int arrayS[2];) имеет оговорку, что если вы объявите эту переменную как часть класса или структуры, она может существовать в любом месте в зависимости от того, как создается класс/структура. (Если класс/структура создается в куче, тогда массив будет находиться в куче, если он создается в стеке, а затем в стеке.)

И, конечно, если он глобальный, то он имеет глобальное хранилище.

Вы предлагаете какой-либо способ повысить эффективность и эффективность моего кода?

Инкапсулируйте концепцию матрицы внутри класса и используйте std::vector вместо выделения собственных массивов. Объем косвенности будет одинаковым после оптимизации компилятора, но вам больше не придется заниматься управлением памятью, используемой массивами.

1

1) Глобальная область, стек и куча расположены в вашем адресном пространстве процессора приложений. Это будет означать, что они находятся в ОЗУ, при условии подкачки по виртуальной памяти (в этом случае они могут пойти и жить на HD на некоторое время) и кэширование ЦП (в этом случае они могут некоторое время переходить на CPU). Но обе эти вещи являются прозрачными по отношению к сгенерированному коду.

2) да, arrayS[2] будет в стеке (если это не глобально, конечно), и все, что возвращается new (или malloc, если вы включите некоторый код C), находится в куче.

3) Я не вижу каких - либо утечек, но если вы собираетесь использовать row и col, а не повторять 2 волшебную константу во всем месте, то сделать это равномерно и помечать их как const, так что вы не можете случайно изменить их.

4) с точки зрения эффективности кеша, может быть лучше сделать одно размещение как new double[col * row] а затем либо распространить ваши указатели на весь этот блок, либо индексировать как [i*col + j], предполагая, что i индексы строки и все строки являются col элементами длиной. new в противном случае разрешено распространять ваши строки, где бы они ни находились в памяти, что, скорее всего, приведет к ошибкам кэша.

Что касается стиля? Ну, вы не спрашивали, но я думаю, что комментарий cdhowie действителен. Также следует глубже рассмотреть точку дедупликатора: у STL есть куча штук, чтобы убедиться, что вы не просачиваете память - читайте на unique_ptr и shared_ptr.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню