2011-01-06 4 views
3

При создании экземпляра класса с новым. Вместо того, чтобы удалить память, какие выгоды мы получим, основываясь на повторном использовании объектов?C++ Использование нового оператора эффективно

Что нового? Возникает ли контекстный переключатель? Выделяется новая память, кто выполняет выделение? ОПЕРАЦИОННЫЕ СИСТЕМЫ ?

+7

Использование другого распределителя, отличного от стандартного, должно основываться на результатах профилирования или на основе дизайна (например, пула памяти). Помимо этого, распределители, которые поставляются с реализациями, в большинстве случаев прекрасны. – AraK

+0

Хороший вопрос. У меня был один случай, когда после профилирования я переключился на распределитель пула для многих объектов малого и постоянного размера. Я думаю, что контекстный переключатель возникает только для выделения нескольких страниц одновременно (с помощью mmap on linux), и эти страницы повторно используются локатором. Теперь существуют разные стратегии распределения, если вы заранее знаете, что объекты, которые вы выделяете, будут иметь одинаковый размер. Стандартные библиотеки-распределители настроены для общего случая, а не для конкретных. Я слышал, что некоторые распределители поддерживают несколько пулов памяти для малых, средних и больших объектов. –

ответ

5

Вы задали несколько вопросов здесь ...

Вместо того, чтобы удалить память, какие выгоды бы мы приобретаем на основе повторного использования объектов?

Это полностью зависит от вашего приложения. Даже если предположить, что я знаю, что такое приложение, вы оставили еще одну деталь неопределенной - какова стратегия повторного использования? Но даже зная, что очень сложно предсказать или ответить в целом. Попробуйте кое-что и измерить их.

Как правило, я хотел бы свести к минимуму наиболее безвозмездное распределение. Однако это преждевременная оптимизация. Это только изменило бы тысячи звонков.

Что нового?

Полностью зависит от реализации. Но общая стратегия, которую используют распределители, состоит в том, чтобы иметь свободный список, то есть список блоков, которые были освобождены в процессе. Когда свободный список пуст или содержит недостаточно непрерывное свободное пространство, он должен запросить ядро ​​для памяти, которое он может выдавать только в блоках с постоянным размером страницы. (4096 на x86.) Распределитель также должен решить, когда нужно нарезать, проложить или объединить блоки. Многопоточность также может оказывать давление на распределителей, поскольку они должны синхронизировать их свободные списки.

Как правило, это довольно дорогостоящая операция. Возможно, не столько по отношению к тому, что еще вы делаете. Но это не дешево.

Возникает ли переключатель контекста?
Полностью возможно. Возможно также, что этого не произойдет. Ваша ОС может свободно переключаться на контекст в любое время, когда получает прерывание или сбой, поэтому ...Это может произойти во много раз; Я не вижу особых отношений между этим и вашим распределителем.

Выделяется новая память, кто выполняет выделение? ОПЕРАЦИОННЫЕ СИСТЕМЫ ?
Это может происходить из бесплатного списка, и в этом случае нет системного вызова, следовательно, никакой помощи от ОС. Но это может произойти из ОС, если бесплатный список не может удовлетворить запрос. Кроме того, даже если это исходит из бесплатного списка, ваше ядро ​​могло бы выгрузить эти данные, чтобы вы могли получить доступ к странице при доступе, и распределитель ядра взорвался. Поэтому я предполагаю, что это будет смешанная сумка. Конечно, вы можете иметь соответствующую реализацию, которая делает все виды сумасшедших вещей.

+0

Существует особая связь с распределителем, ядром и замками. Если недостаточно памяти кучи, очевидно, задействован syscall, который будет выполнять контекстный переключатель. Если доступ к куче должен быть сериализован, тогда задействуется блокировка, которая может снова потребовать переключения режима селектора и контекста. Для высокопроизводительных приложений этот возможный системный вызов важен - даже если в большинстве случаев он этого не сделает. –

2
  • новый выделяет память для класса в куче и вызывает конструктор.
  • Переключатели контекста не обязательно должны возникать.
  • C++ - runtime выделяет память на своем freestore, используя любой механизм, который он считает нужным.

Обычно среда выполнения C++ выделяет большие блоки памяти с использованием функций управления памятью ОС, а затем подразделяет их вверх, используя собственную реализацию кучи. В среде выполнения microsoft C++ в основном используются функции кучи Win32, которые реализованы в usermode, и разделяют память ОС, выделенную с помощью apis виртуальной памяти. Таким образом, нет контекстных переключателей до тех пор, пока не потребуется его текущее распределение виртуальной памяти, и ему нужно перейти на ОС, чтобы выделить больше.

Существует теоретическая проблема при распределении памяти, что нет верхней границы того, как долго может пройти обход кучи, чтобы найти свободный блок. Практически такие распределения кучи обычно бывают быстрыми.

За исключением резьбовых приложений. Поскольку большинство C++ runtimes используют одну кучу между несколькими потоками, доступ к куче должен быть сериализован. Это может сильно ухудшить производительность определенных классов приложений, которые полагаются на несколько потоков, способных к новым и удалять многие объекты.

+0

glibc имеет распределитель, который не деградирует в многопоточных приложениях. –

+0

это приятно знать. msvc, с другой стороны, использует распределитель os, а до NT 6.1 он не работал хорошо. –

1

Если вас new или delete адрес, он отмечен как оккупировали или неприсвоенное. Реализации не говорят все время с ядром . Большие патроны памяти зарезервированы и делятся на меньше патроны в пространстве пользователя в вашем приложении.

Поскольку new и deleteявляется Реентрантными (или поточно-в зависимости от реализации) переключение контекста может иметь место, но ваша реализация потокобезопасна в любом случае при использовании по умолчанию new и delete.

В C++ вы можете перезаписать оператор new и delete, например. для управления памятью:

#include <cstdlib> //declarations of malloc and free 
#include <new> 
#include <iostream> 
using namespace std; 

class C { 
public: 
    C(); 
    void* operator new (size_t size); //implicitly declared as a static member function 
    void operator delete (void *p); //implicitly declared as a static member function 
}; 

void* C::operator new (size_t size) throw (const char *){ 
    void * p = malloc(size); 
    if (p == 0) throw "allocation failure"; //instead of std::bad_alloc 
    return p; 
} 

void C::operator delete (void *p){ 
    C* pc = static_cast<C*>(p); 
    free(p); 
} 

int main() { 
    C *p = new C; // calls C::new 
    delete p; // calls C::delete 
} 
Смежные вопросы