#c #linux #garbage-collection #g
#c #linux #сбор мусора #g
Вопрос:
Я хочу разработать многопоточное приложение на C (где в конечном итоге большая часть кода на C будет генерироваться самим приложением, которое можно рассматривать как язык, специфичный для домена высокого уровня) на Linux / AMD64 / Debian с GCC 4.6 (и, вероятно, последним стандартом C 11).
Я действительно хочу использовать консервативный сборщик мусора Boehm для всех моих распределений кучи, потому что я хочу распределять с new(GC)
и никогда не беспокоиться об delete
. Я предполагаю, что GC Boehm работает достаточно хорошо.
Основная мотивация для использования C (вместо C) — это все алгоритмы и коллекции std::map
… std::vector
предоставляется стандартной библиотекой C .
GC Boehm предоставляет gc_allocator<T>
шаблон (в его файле gc/gc_allocator.h).
Должен ли я переопределить operator ::new
как Boehm’s one?
Или я должен использовать все шаблоны коллекции с явным аргументом шаблона распределителя, установленным на some gc_allocator
? Я не совсем понимаю роль второго аргумента шаблона (распределителя) для std::vector? Используется ли он для выделения векторных внутренних данных или для выделения каждого отдельного элемента?
А как насчет std::string
-s? Как сделать их данные распределенными для общего доступа? Должен ли я иметь свою собственную строку, используя basic_string
шаблон с gc_allocator
? Есть ли какой-нибудь способ получить внутренние массивы символов, выделенные с помощью GC_malloc_atomic
not GC_malloc
?
Или вы советуете не использовать Boehm GC с приложением, скомпилированным на g ?
С уважением.
Комментарии:
1. Все зависит от того, насколько вы знакомы с C и хороши в нем. Можете ли вы написать приличную программу на C без использования
delete
, и понимаете ли вы, чтоnew
об этом следует говорить только в очень, очень особых обстоятельствах, и что указатели по большей части не нужны? Если вы понимаете все это и приходите к выводу, что вам требуется сборщик мусора, тогда, во что бы то ни стало, продолжайте. С другой стороны, если вы этого не сделаете, вы можете обнаружить, что идиоматичный современный C довольно хорош в удобном для пользователя детерминированном управлении памятью.2. Хе-хе-хе — возможно, я здесь перегибаю палку, но мне кажется, что если вы знаете сбор мусора, но не очень хорошо знаете C , то это классическая ситуация «у меня есть молоток»… Почему бы не опубликовать типичный фрагмент кода, и мы сможем увидеть, как это сделать способом C ?
3. Хм. Вам действительно нужно выбрать один. Это разные языки. Когда вы генерируете код на C и делаете это правильно, я бы сказал, что вам не нужен сборщик мусора, и вы должны доказать, зачем он вам понадобился бы . (Ваш компилятор вполне может использовать один, но сейчас я говорю о результирующем коде.)
4. Честно говоря, я думаю, что слишком много вопросов. Лучше всего быть сфокусированным и конкретным. Если быть предельно честным, если вы не очень хорошо знакомы с механикой распределителя C , вам, вероятно, преждевременно разрабатывать инструмент генерации кода C , и вы должны хорошо понимать язык, на который вы переводите, прежде чем приступать к такому предприятию. Это всего лишь мое личное впечатление, и я желаю вам удачи и смелости в этом — я просто думаю, что изучение большего количества C на некоторое время было бы беспроигрышным для всех.
5. Проще говоря, вообще нет причин для
new
прямого использования и никогда не было причин дляdelete
чего-либо. Судя по вашему сообщению, у меня осталось отчетливое впечатление, что вы совершенно не представляете, как вообще писать код на C , и не используете конструкции, предоставляемые в качестве стандарта, и используете GC просто потому, что это парадигма, к которой вы привыкли.
Ответ №1:
Чтобы частично ответить на мой собственный вопрос, следующий код
// file myvec.cc
#include <gc/gc.h>
#include <gc/gc_cpp.h>
#include <gc/gc_allocator.h>
#include <vector>
class Myvec {
std::vector<int,gc_allocator<int> > _vec;
public:
Myvec(size_t sz=0) : _vec(sz) {};
Myvec(const Myvecamp; v) : _vec(v._vec) {};
const Myvecamp; operator=(const Myvec amp;rhs)
{ if (this != amp;rhs) _vec = rhs._vec; return *this; };
void resize (size_t sz=0) { _vec.resize(sz); };
intamp; operator [] (size_t ix) { return _vec[ix];};
const intamp; operator [] (size_t ix) const { return _vec[ix]; };
~Myvec () {};
};
extern "C" Myvec* myvec_make(size_t sz=0) { return new(GC) Myvec(sz); }
extern "C" void myvec_resize(Myvec*vec, size_t sz) { vec->resize(sz); }
extern "C" int myvec_get(Myvec*vec, size_t ix) { return (*vec)[ix]; }
extern "C" void myvec_put(Myvec*vec, size_t ix, int v) { (*vec)[ix] = v; }
при компиляции с g -O3 -Wall -c myvec.cc
создается объектный файл с
% nm -C myvec.o
U GC_free
U GC_malloc
U GC_malloc_atomic
U _Unwind_Resume
0000000000000000 W std::vector<int, gc_allocator<int> >::_M_fill_insert(__gnu_cxx::__normal_iterator<int*, std::vector<int, gc_allocator<int> > >, unsigned long, int constamp;)
U std::__throw_length_error(char const*)
U __gxx_personality_v0
U memmove
00000000000000b0 T myvec_get
0000000000000000 T myvec_make
00000000000000c0 T myvec_put
00000000000000d0 T myvec_resize
Таким образом, в сгенерированном коде нет простого malloc или ::operator new
.
Таким образом, используя gc_allocator
и new(GC)
, я, по-видимому, могу быть уверен, что обычный ::opertor new
or malloc
не используется без моего ведома, и мне не нужно переопределять ::operator new
дополнения (январь 2017)
Для дальнейшего использования (спасибо Sergey Zubkov за упоминание об этом в Quora в комментарии) см. Также n2670 и <memory>
и поддержку сборки мусора (например, std::declare_reachable, std::declare_no_pointers, std::pointer_safety и т. Д.). Однако это не было реализовано (за исключением тривиального, но приемлемого способа сделать это без операции) в текущем GCC или Clang на наименьший.