«Грубо говоря», только new, с настройками по умолчанию (+ еще 100500 оговорок) — в java скорей всего быстрее. В С++/С наверняка можно выжать и быстрее — но надо быть джедаем + опять же «грубо говоря», потратить месяц на ускорение на 1 секунду на час работы.
А вообще, практически наверняка, в вашей программе есть более практичные места для починки.
А зачем это вообще? (сейчас плеваться начнут) В С/С++ память стараются не выделять (дефолтным аллокатором) там, где надо, чтобы кусок кода быстро работал. То есть, на практике такое сравнение не встречается.
Грубо говоря где «new» работает быстрее ? В С++ или java/C# ?
Надо считать не только new, а new+delete vs. new+GC.
Аллокатор рантайма с GC тратит больше на походы к ядру за счёт того, что просто GC требует в 2-3 раза больше памяти (в среднем по больнице), чем unmanaged. Но эти расходы относительно лёгкие по затратам, даже с учётом обнуления страниц и т.п.
А вот накладные расходы на каждый элемент, видимый программисту (объект в JVM/etc., или объект по new/delete) — с современными VM в среднем немного дешевле (а иногда и ненамного).
Исправлять это можно за счёт собственного аллокатора, но тогда все проблемы по управлению этим ложатся на программиста.
Ещё у GC проблема неравномерности, в некоторых применениях это критично.
А как обстоят дела когда код из байт, транслирован в машинный ?
Без разницы. Чуть ускоряется new (его могут инлайнить), а GC не транслируется в машинный, он уже там.
Примерно одинаковы. Но я советую оценить приблизительно, сколько миллионов таких аллокаций сделает твой код за жизнь. Миллион? Сто миллионов? Миллиард? Десять миллиардов? А теперь запусти цикл на 10 миллиардов аллокаций, и потом скажи — стоило ли оно, оптимизировать 1 минуту работы одного процессора — именно столько ты рискуешь «перерастратить».
Не делай за компьютер его работу. Лучше разберись где дебаг быстрее, и где цена ошибки дешевле.
Единственный интересный коммент в теме. Расскажи ка чем это у JVM алокация лучьше? JIT компиляция? А она чем-то помогает в алокации памяти? Еще мне в голову приходит то, что в управляемых языках сборщик мусора может заниматься и дефрагментацией памяти, что как бы упрощает алокацию, но с другой стороны и само по себе требует ресурсов. Таки какие ваши аргументы?
по моим понятиям нативный аллокатор делает примерно то же самое. Я встречал аргумент, что все алокаторы ± одинаковые, как только что-то революционное имплементируется в одном месте, так тут же перетекает и в другие места.
Обычный нативный аллокатор — выделяет память «в куче» при каждом обращении. И возвращает указатель на память.
Плэйсмент-аллокатор — выделяет память «в куче» 1 раз. А далее, все выделения происходят на уже выделенном куске, что гораздо быстрее, чем выделять «в куче».
П.С. Как правило, если показывают какой-нибудь бэнчмарк, по которому код Джава работает быстрее, чем код C/C++ — ищи в тесте множественные выделения памяти.
по моим понятиям нативный аллокатор делает примерно то же самое.
у JVM при выделении памяти проверок меньше. там утрировано — выдал указатель на начало, сдвинул указатель на занимаемое число байт. и все. освобождением памяти и дефрагментацией потом GC займется. классический же malloc бродит по куче, ищет близкий по размеру свободный блок. опять же утрировано :) потому что — стандарта нету, и запрашивать у операционки память для каждой мелочевки — глупо.
всякая уважающая себя либа, или фреймворк имеют свой аллокатор, схожий по принципу работы с описанным у JVM. с нюансами конечно, потому что GC то нету. помню GTKшный какой-то смотрел, там через malloc запрашиваются крупные блоки. а уже в них — двигают указатели. и соглашения по освобождению имеются.
и для new — тоже. поэтому вообще говоря даже не от компилятора зависит — а какую библиотеку подцепил, работающую поверх штатного malloc — так и будет.
а вот если new умеет выделять память на стеке, потому что компилятор видит что эта память будет не нужна после выхода из процедуры, от тут да.
всякая уважающая себя либа, или фреймворк имеют свой аллокатор, схожий по принципу работы с описанным у JVM. с нюансами конечно, потому что GC то нету.
Есть boehm-gc и ещё полдесятка чуть пожиже проектов GC для C/C++. У них меньше возможностей, часто они «консервативные» (этим забавным словом обозначают то, что они не в состоянии анализировать, где в памяти указатель, а где просто похожие данные, и могут случайным образом сохранять лишнее), но они есть. Та же Mozilla в браузерах его активно использовала (использует?)
У меня нет аргументов, полагаюсь на чужое мнение, которое не проверял. Но в целом встроенный аллокатор виртуальной машины мне представляется более элегантным решением, чем поход за каждым байтом хипа к ядру.
Смысл слова «гипербола» известен? Ок, за каждой страницей. И да, насколько я осведомлен — принципы реализации malloc не регулируются никаким стандартом и остаются на совести авторов конкретной реализации стандартной библиотеки.
Вот именно malloc не регулируется никаким стандартом и следовательно зависит от конкретной реализации стандартной библиотеки. malloc может за один раз запросить одну страницу у ядра, а может и 101, про запас. Также на ++ можно написать свой собственный аллокатор памяти, что собственно и делают многие проекты. Если очень хочется то можно реализовать свой собственный сборщик мусора.
Почему? Как правило хип реализован маленькими аренами по 256-1024Кб, когда арена заканчивается выделяется следующая память у ОС. Если запросить сразу большой кусок, то выделение памяти минует арену и сразу пойдёт к ОС. Если операционка с глупыми настройками по дефолту, типа линукса, то выделение памяти будет каждую страницу при первом доступе.
то есть такой линейный ползюк по остатку большой области.
Потом приходит GC, быстро пропускает ~95% объектов (потому что 0-е поколение и там почти все — одноразовые), а остальные сжимает и выставляет новую границу.
malloc/new, в отличие от них, занимаются поиском свободной дырки адекватного размера. Это операция долгая, скучная, очень часто недружелюбная к кэшу.
GC тем быстрее, чем больше можно занять памяти по сравнению с собственно суммой размеров объекта — тогда перемещать надо мало и легко. Ну и чем больше он может потратить времени за раз (всякие инкрементальные и параллельные всегда заметно дороже).
JIT компиляция?
Нет, она ни при чём.
Еще мне в голову приходит то, что в управляемых языках сборщик мусора может заниматься и дефрагментацией памяти, что как бы упрощает алокацию, но с другой стороны и само по себе требует ресурсов.
Да. Тем не менее суммарные ресурсы на него оказываются, по многим сообщениям, в итоге меньше.
36 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів-
«Грубо говоря», только new, с настройками по умолчанию (+ еще 100500 оговорок) — в java скорей всего быстрее. В С++/С наверняка можно выжать и быстрее — но надо быть джедаем + опять же «грубо говоря», потратить месяц на ускорение на 1 секунду на час работы.
А вообще, практически наверняка, в вашей программе есть более практичные места для починки.
а в чем разница между «конкретно» new в С++ или java или C#? вы же говорите только про выделение памяти?
А зачем это вообще? (сейчас плеваться начнут) В С/С++ память стараются не выделять (дефолтным аллокатором) там, где надо, чтобы кусок кода быстро работал. То есть, на практике такое сравнение не встречается.
Надо считать не только new, а new+delete vs. new+GC.
Аллокатор рантайма с GC тратит больше на походы к ядру за счёт того, что просто GC требует в2-3 раза больше памяти (в среднем по больнице), чем unmanaged.
Но эти расходы относительно лёгкие по затратам, даже с учётом обнуления страниц и т.п.
А вот накладные расходы на каждый элемент, видимый программисту (объект в JVM/etc., или объект по new/delete) — с современными VM в среднем немного дешевле (а иногда и ненамного).
Исправлять это можно за счёт собственного аллокатора, но тогда все проблемы по управлению этим ложатся на программиста.
Ещё у GC проблема неравномерности, в некоторых применениях это критично.
Без разницы. Чуть ускоряется new (его могут инлайнить), а GC не транслируется в машинный, он уже там.
Примерно одинаковы. Но я советую оценить приблизительно, сколько миллионов таких аллокаций сделает твой код за жизнь. Миллион? Сто миллионов? Миллиард? Десять миллиардов? А теперь запусти цикл на 10 миллиардов аллокаций, и потом скажи — стоило ли оно, оптимизировать 1 минуту работы одного процессора — именно столько ты рискуешь «перерастратить».
Не делай за компьютер его работу. Лучше разберись где дебаг быстрее, и где цена ошибки дешевле.
Аллокація об’єктів — для лохов. Використовуй пул.
Алокації — завжди не дуже швидкі, хоч як. Треба швидко — алокуйте пул і з нього потім тягніть.
1. нью для лохов. Пользуй маллок/реаллок.
2. Если пользуешь нью — пользуй его, как «плейсмент».
Тогда всё будет быстро.
Зависит от аллокатора памяти.
Поговаривают, что у JVM таки лучше.
Единственный интересный коммент в теме. Расскажи ка чем это у JVM алокация лучьше? JIT компиляция? А она чем-то помогает в алокации памяти? Еще мне в голову приходит то, что в управляемых языках сборщик мусора может заниматься и дефрагментацией памяти, что как бы упрощает алокацию, но с другой стороны и само по себе требует ресурсов. Таки какие ваши аргументы?
B виртуальных машинах «плэйсмент констракшн». Отгрызают кусок памяти при старте — и дальше в нём живут. Если не хватает — отгрызают ещё.
по моим понятиям нативный аллокатор делает примерно то же самое. Я встречал аргумент, что все алокаторы ± одинаковые, как только что-то революционное имплементируется в одном месте, так тут же перетекает и в другие места.
Обычный нативный аллокатор — выделяет память «в куче» при каждом обращении. И возвращает указатель на память.
Плэйсмент-аллокатор — выделяет память «в куче» 1 раз. А далее, все выделения происходят на уже выделенном куске, что гораздо быстрее, чем выделять «в куче».
П.С. Как правило, если показывают какой-нибудь бэнчмарк, по которому код Джава работает быстрее, чем код C/C++ — ищи в тесте множественные выделения памяти.
Куча в куче.
Ок, назовем выделенный кусок кучей — сразу станет тормозить?
Под «кучей» я имел в виду динамически-выделяемую память (в отличии от стэка).
у JVM при выделении памяти проверок меньше. там утрировано — выдал указатель на начало, сдвинул указатель на занимаемое число байт. и все. освобождением памяти и дефрагментацией потом GC займется.
классический же malloc бродит по куче, ищет близкий по размеру свободный блок. опять же утрировано :) потому что — стандарта нету, и запрашивать у операционки память для каждой мелочевки — глупо.
всякая уважающая себя либа, или фреймворк имеют свой аллокатор, схожий по принципу работы с описанным у JVM. с нюансами конечно, потому что GC то нету. помню GTKшный какой-то смотрел, там через malloc запрашиваются крупные блоки. а уже в них — двигают указатели. и соглашения по освобождению имеются.
и для new — тоже.
поэтому вообще говоря даже не от компилятора зависит — а какую библиотеку подцепил, работающую поверх штатного malloc — так и будет.
а вот если new умеет выделять память на стеке, потому что компилятор видит что эта память будет не нужна после выхода из процедуры, от тут да.
Есть boehm-gc и ещё полдесятка чуть пожиже проектов GC для C/C++. У них меньше возможностей, часто они «консервативные» (этим забавным словом обозначают то, что они не в состоянии анализировать, где в памяти указатель, а где просто похожие данные, и могут случайным образом сохранять лишнее), но они есть.
Та же Mozilla в браузерах его активно использовала (использует?)
У меня нет аргументов, полагаюсь на чужое мнение, которое не проверял.
Но в целом встроенный аллокатор виртуальной машины мне представляется более элегантным решением, чем поход за каждым байтом хипа к ядру.
Менеджер памяти в С++ (как и любой другой язык) не обращается к ядру за каждым байтом.
Смысл слова «гипербола» известен?
Ок, за каждой страницей.
И да, насколько я осведомлен — принципы реализации malloc не регулируются никаким стандартом и остаются на совести авторов конкретной реализации стандартной библиотеки.
Вот именно malloc не регулируется никаким стандартом и следовательно зависит от конкретной реализации стандартной библиотеки. malloc может за один раз запросить одну страницу у ядра, а может и 101, про запас. Также на ++ можно написать свой собственный аллокатор памяти, что собственно и делают многие проекты. Если очень хочется то можно реализовать свой собственный сборщик мусора.
Спасибо кэп, чтоб я делал без вас.
Однако где же вы видели поход к ядру за каждым байтом?
Вызовы malloc и new до ядра не доходят
Почему? Как правило хип реализован маленькими аренами по 256-1024Кб, когда арена заканчивается выделяется следующая память у ОС. Если запросить сразу большой кусок, то выделение памяти минует арену и сразу пойдёт к ОС. Если операционка с глупыми настройками по дефолту, типа линукса, то выделение памяти будет каждую страницу при первом доступе.
Ок, обычно не доходит. Если хип уже есть и в нем есть подходящий кусок
Тем, что она выглядит в духе
#define OBJECT_HEADER_SIZE 16 size_in_mem = object_size + OBJECT_HEADER_SIZE; if (unlikely(heap_pos + size_in_mem >= heap_limit)) { gc_or_die(); } object_addr = *heap_pos; heap_pos += size_in_mem;то есть такой линейный ползюк по остатку большой области.
Потом приходит GC, быстро пропускает ~95% объектов (потому что0-е поколение и там почти все — одноразовые), а остальные сжимает и выставляет новую границу.
malloc/new, в отличие от них, занимаются поиском свободной дырки адекватного размера. Это операция долгая, скучная, очень часто недружелюбная к кэшу.
GC тем быстрее, чем больше можно занять памяти по сравнению с собственно суммой размеров объекта — тогда перемещать надо мало и легко. Ну и чем больше он может потратить времени за раз (всякие инкрементальные и параллельные всегда заметно дороже).
Нет, она ни при чём.
Да. Тем не менее суммарные ресурсы на него оказываются, по многим сообщениям, в итоге меньше.
А який компілятор ?
ІМХО, від цього все залежить.
а что между майкрософтовским,интеловским и gcc есть такая существенная разница ?
Хз, треба міряти, також логіка підказує, що може сильно залежати від конкретної пам"яті на конкретному пристрої.
Тогда это дело runtime library, а не компилятора.
А какая разница?
если когда то пытался изучать ассемблерХ86, то разница есть.
Я вроде-бы даже не только пытался, но и немного приуспел.
ИМХО вопрос сам по себе безсмысленный.
Как связна ассемблер с аллокацией памяти ?
В чем смысл вопроса? Вы что, выбираете язык для написания чего-то по скорости аллокатора? это же бессмыслица