• Какой смысл команды dup в JVM байт коде? И что за индексы локальных переменных?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Java
    Седой и строгий
    Когда разрабатываешь сложные системы, стоит оперировать простыми абстракциями. А виртуальная машина - это очень сложно. Попытки кроилова на количестве операций в байткоде приведут к необходимости писать более сложный, менее стабильный и менее производительный код виртуальной машины.

    Значения локальных переменных хранятся в нативном массиве, выделяемом в каждом кадре стека вызовов. Для примитивных типов в нём хранятся сами значения, для ссылочных - ссылки в кучу. На этапе генерации байткода потому нельзя впихивать напрямую адреса, что байткод должен быть переносимым, неизвестно как может быть устроена память машин, на которых его могут выполнять.
    Ответ написан
    1 комментарий
  • Почему StringBuilder при вызове метода ToString() копирует содержимое?

    Alexeytur
    @Alexeytur
    String и char[] это разные вещи с точки зрения среды выполнения. char[] это изменяемый объект, можно по индексу изменить значение отдельного элемента. String это неизменяемый объект, операции изменения строки на самом деле создают копии оригинального объекта строки.
    Поэтому, если нужно создать строку через множество операций, используют StringBuilder, чтобы не было множества выделений/освобождений памяти.
    Ответ написан
    Комментировать
  • Как в runtime вставить в метод код, рефлексия, кодогенерация?

    Есть два варианта:
    https://www.postsharp.net/
    https://github.com/Fody/Fody
    А вот в рантайме, емнип, нельзя менять код.
    Но можно сгенерировать абсолютно новый код (новый класс с новым методом) через System.Reflection.Emit
    Ответ написан
    Комментировать
  • Что происходит во время прерывания в многопоточной среде? Или прерывания посреди прерывания?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    откуда прерывания знают адрес, куда им вернуть результат.

    Прерывания не знают. Это работа ОС -- организовать информацию так, чтобы при получении прерывания разобраться, откуда оно, зачем, и что с ним делать.

    Прерывание в коде int 21h и прочие Это какое?

    Любое прерывание инициируемое инструкцией int -- программное. В отличие от прерывания, инициируемого уровнем или фронтом сигнала подключённого к контроллеру прерываний.

    Вообще, кажется, если понять, что программные прерывания на x86 используются просто как удобный способ вызывать функции ядра, т.е. делать системные вызовы, то путаницы должно стать меньше. Не думай о них как о прерываниях, думай о них просто как о вызовах функций ядра. Ядро делает всё для того, чтобы для приложения это именно так и выглядело.

    выполнение прерывания std::cin>>line; Может и сутки длиться.

    Системного вызова. std::cin >>line в конце концов превращается в системный вызов read.

    Вот как по пунктам для этой команды. (С условием что есть еще 1 поток жаждущий ЦП).

    Можно запустить такую программу, узнать её PID, выполнить где-нибудь cat /proc/<PID>/stack и увидеть следующую картину:
    [<0>] wait_woken+0x67/0x80
    [<0>] n_tty_read+0x426/0x5a0
    [<0>] tty_read+0x135/0x240
    [<0>] new_sync_read+0x115/0x1a0
    [<0>] vfs_read+0xf4/0x180
    [<0>] ksys_read+0x5f/0xe0
    [<0>] do_syscall_64+0x33/0x80
    [<0>] entry_SYSCALL_64_after_hwframe+0x44/0xa9

    Т.е. поток выполнил системный вызов (ksys_read), зашёл в VFS, добрался до функции чтения в драйвере терминала (tty_read) и перешёл в состояние ожидания в глубине этой функции (wait_woken). Когда драйвер терминала получит данные для программы, он разбудит её поток и системный вызов завершится. До тех пор этот поток будет не готов к выполнению и скедулер ОС просто не будет выделять ему время.

    Мне кажется, что тебе было бы полезно прочитать вторую и третью книжки (Understanding the Linux Kernel и Linux Kernel Developmen) из моего списка.
    Ответ написан
    Комментировать
  • Как происходит доступ к эл. массива на уровне ядра? Malloc выделяет непрерывную физическую память?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как происходит доступ к эл. массива на уровне ядра?

    Так же как и на уровне приложения -- через трансляцию виртуального адреса в физический.

    Например массив Int* arr = new int[1024*1024*1024] он как храниться?

    Если мы для определённости возьмём linux, то у ядра есть несколько разных способов выделения памяти, в зависимости от того, для чего эта память выделяется. Есть наиболее простой и стандартный kmalloc который выделяет память непрерывную как виртуально так и физически. Обычно этим механизмом нельзя выделить большой непрерывный кусок. Есть vmalloc, который выделяет непрерывную виртуально, но возможно прерывную физически память. Есть get_free_pages который выделяет непрерывные страницы физической памяти, возможно, не отображаемые ни в какие виртуальные адреса. Есть Contiguous Memory Allocator который при старте системы резервирует кусок непрерывной физической памяти и может аллоцировать оттуда куски по запросу.
    Важный момент состоит в том, что аллокации делаемые ядром linux через упомянутые интерфейсы всегда обеспечиваются физической памятью, у памяти ядра нет пейджинга.

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

    Почему быстрее? С точки зрения процессора всё равно будет трансляция виртуального адреса в физический, если повезёт -- попадание в TLB, если не повезёт -- ходить по каталогам и таблицам страниц в памяти.

    получается эмулятор каждый адрес вычислять что ли?

    Простой эмулятор -- да, наверно. Умный эмулятор может кешировать эту информацию, например именно это свойство даёт QEMU большую часть его Q.
    Ответ написан
    Комментировать
  • Зачем нужно выравнивание памяти? Точнее, почему процессор обращается 2 раза к невыравниным данным?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Вопрос такой что отвечая на него можно новую книгу написать. Тут даже С не причем. А причем - архитектура процессора x86. Кстати тут еще надо кеш-линии рассмотреть. Это фокус такой. Что если тебе надо 1 байт прочитать
    из произвольного адреса, современная архитектура этого не умеет. Она читает (обычно) кусок памяти шириной в 64 байта. Это обзывается кеш-линия. И уже из нее будет прочитан нужный байт. Отвечающие верно сказали выше. Еще можно добавить такое (условное правило) что тип данных должен лежать в сегменте данных по адресу кратному самому размеру типа. Тоесть int должен лежат на адресах кратных 4, long - 8 байт и так далее. Вот насчет MMX/SSE не знаю.
    Ответ написан
    1 комментарий
  • Как оптимально организовать структуру памяти, Кучу? Как она реализована в виртуальных машинах?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Там не происходиит копирование данных. Просто среда выаолнения запоминает, что переменная a лежит вон там внутри "массива" кучи. При чтении оттуда данных все происходит за одну асскмблерную операцию, как если бы вы читали из int.

    Пишущим на си++ из-за концепции указателей это все должно быть понятнее. При выделении данных на куче просто какой-то указатель указывает куда-то в кучу и все.
    Ответ написан
    Комментировать
  • Как именно работает Сумматор в процессоре? Сигналы же не могут одновременно прийти, то есть будет 2 работы?

    @nehrung
    Не забывайте кликать кнопку "Отметить решением"!
    Я уже отвечал недавно на вопрос, как работает сумматор, и вопрос этот был ваш. Видимо, вы не поняли мой ответ, хотя мне казалось, он сформулирован достаточно просто. Ну что ж, придётся разжёвывать.
    Прежде всего, сам по себе сумматор - комбинационная цифровая схема, и как таковой, он в тактовых импульсах не нуждается. Подали на его входы два операнда, и спустя время задержки на выходе появляется сумма. Но разжуём уже до мельчайших косточек - возьмём идеальный сумматор, составленный из идеальных логических элементов, не имеющих задержек распространения сигнала. Исходное состояние - на входах нули. На выходе, естественно, тоже нуль. Подаём первый операнд. Задержек нет, поэтому на выходе тут же появляется этот же операнд (он суммировался с нулём на другом входе). Затем подаём второй операнд - на выходе тут же (т.е. опять-таки без задержек) появляется сумма. Надеюсь, тут всё понятно (собственно, это мой ответ на эти ваши 0.0000000001 секунды - да хоть 0.00000000000000000000000000000001 сек, в идеальном сумматоре это без разницы).
    Теперь рассмотрим сумматор из реальных логических элементов, имеющих задержку распространения. В нём всё точно так же, вот только на время суммарной задержки его составных частей на выходе будет неизвестно что. Вот так, буквально - подали первый операнд, на выходе неизвестно что (какая-то каша, которой нельзя доверять), и спустя время задержки каша успокаивается, и мы обнаруживаем на выходе этот самый первый операнд, который суммирован с нулём. Подали второй операнд - то же самое: сумму видим на выходе, когда период задержек закончился.
    Именно по этой причине реальный сумматор в реальном процессоре снабжается входными и выходным регистрами - они позволяют отсеять те его состояния, которым нельзя доверять. Записали в первый регистр первый операнд по тактовому импульсу 1, затем второй по импульсу 2 (впрочем, можно и одновременно), и только потом по тактовому импульсу 3 записываем сумму в выходной регистр и пускаем дальше туда, где она понадобилась. Время между тактами должно быть заведомо больше, чем общие задержки в сумматоре - только при этом условии мы можем быть уверены в точности его работы. Попытки уменьшить тактовое время (мол, вот я счас сделаю мой проц более быстрым) неизбежно приведут к сбоям, т.е. к ошибкам в вычислениях.
    Теперь понятно? Если всё ещё нет, задавайте вопросы, только не в виде программного кода - на этом уровне рассмотрения он не нужен.
    И ещё: вы сделали два одинаковых вопроса - так тут не делается. Настоятельно советую удалить второй, который сейчас заблокирован.
    Ответ написан
    2 комментария
  • Каким образом физически устроена модель памяти? И физическая реализация простых логических операций?

    hint000
    @hint000
    у админа три руки
    Если нету тока, то как сохраняется 1. После отключение от сети.
    в ОЗУ сохраняется только при наличии питания, а в динамическом ОЗУ (DRAM) при наличии не только питания, но и сигнала регенерации. Без питания сохраняется либо в ПЗУ, либо в flash, либо на магнитных носителях (магнитные диски, магнитные ленты), либо на оптических носителях. Рассказывать про все эти технологии долго, зато в сети дофига можно найти по каждой из них (важно: "слона нужно есть по кусочкам", не собирайте всё в кучу, технологии очень разные физически, ознакомьтесь с одной, потом переходите к другой).
    Если выключить компьютер на 20 лет, или замуровать процессор с ROM памятью на миллион лет(при условии что он не развалиться). Там даже микрокод разрядиться?
    Через 20 лет flash может не прочитаться (как повезёт), CD-R\DVD-R могут не прочитаться (как повезёт, но CD-RW\DVD-RW наверняка не прочитаются), всё остальное сохранится без проблем, наверняка. На миллион лет не сохранит информацию вообще ни одна из современных технологий, только на каменных плитах высекать текст. На тысячу лет - считается, что практически ни одна технология не гаратирует сохранение, хотя для этой https://ru.wikipedia.org/wiki/M-DISC
    заявлен как раз срок хранения 1000 лет, но ведь нет возможности проверить, врут или не врут. Структуры в кремнии деградируют тем быстрее, чем тоньше технологический процесс. Т.е. очень старые процессоры теоретически могут сохранить работоспособность гораздо дольше, чем современные. И да, в частности, микрокод может повредиться, но даже если микрокод заново прошить, то всё равно процессор может работать со сбоями или вовсе не будет работать.
    Какой ток используется. Пишут что постоянный. Это как понять, если ток постоянный, то не будет сигналов же?
    Под "постоянным" здесь подразумевают, что полярность не меняется. Возьмите фонарик на батарейках. Можно щёлкать выключателем и подавать кому-то световые сигналы. Но никто не скажет, что фонарик питается от батареек переменным током. Это коммутация, а не переменный ток.
    Ответ написан
    Комментировать
  • Каким образом физически устроена модель памяти? И физическая реализация простых логических операций?

    mayton2019
    @mayton2019
    Bigdata Engineer
    (Ответ есть ток, нету. Чет вообще не понятен, к примеру поражает вопрос а как Логический НЕ, инвертор из 0 -> 1 делает то? )
    Что означат 1 при работе, что означает 0? Большинство схем сигналов рисуют синусоиду от (-A,A) или (-1;1)

    Вопрос интересный. Он стоит просто на стыке определений. В системотехнике логическим нулем и единицей просто принято считать уровни напряжения. Один повыше. Другой пониже (хотя не ноль). На диаграммах напряжений (если смотреть осцилографом) прямоугольных импульсов вообще не бывает. Они все - сглаженные. Фронт импульса имеет какую-то гладкость. И это вносит микро-задержки в обработку. Это кстати главная причина почему бесконечно длинные провода не могут передавать цифровой сигнал. Они - имеют емкость. Как конденсатор. Паразитную емкость. И это - проблема.

    Цифровые вентили И-ИЛИ-НЕ это обычные аналоговые схемы которые просто обладают двумя устойчивыми состояниями. Как весы. Или качнутся вправо. Или резко влево. Но по центру не зависают никогда.

    В цифовой передаче данных еще интереснее. Коды типа Манчестерского которые ты каждый день используешь в Ethernet кабелях - двухполярные и еще и обладают свойством нулевого дрейфа постоянного тока. Тоесть это тоже цифровой сигнал где есть единички и нули но сверху над ним огромная электрическая аналоговая теория которая просто оптимизирует его работу в части приема-передачи и защиты от помех.

    Короче цифровой и дискретный - это метафоры. Которые построены поверх обычно аналоговй техники которая лишь иногда (!) ведет себя как цифровая. Нам просто удобно это называть цифровым чтоб программировать. Алан Тюьринг например строил ЭВМ не реле. Это электромеханические электромагниты которые тоже решали задачи вентилей И-ИЛИ-НЕ и обладаи памятью (обычно 1 бит).

    Вобщем если ты хочешь прозреть по настоящему - почитай вообще про "аналоговую" радиотехнику. Ты будешь просто поражен простотой некоторых решений. Например операционный усилитель может умножать числа. Ну... как числа. Напряжения :)
    Ответ написан
    Комментировать
  • Каким образом физически устроена модель памяти? И физическая реализация простых логических операций?

    @atereffigies
    1. ПЗУ и ОЗУ бывают разных типов, и хранится информация там по-разному. Статическое ОЗУ, например, это матрица, состоящая из D-защёлок. Динамическое ОЗУ хранит инфу в емкости затвора транзистора, как и память типа ФЛЕШ, но флеш устроена по-другому. Классические ПЗУ вообще просто имеют матрицу соединений, которые пережигаются однократно при прошивке.
    2. 0 и 1 -- это не про ток, а про напряжение. Обычно, низкий уровень напряжения это нуль, а высокий -- единица. Синусоиды -- это вообще аналоговый сигнал, при чем здесь логика?
    3. Если инфа зашита жестко в кремнии, то она просуществует долго. Если это флеш-память, то через какое-то время она станет нечитаемой.
    4. Используется где?
    5. Если вы не знаете, как работает обычный транзистор, то не имеет смысла задавать подобные вопросы, иначе отвечающему придётся вас погрузить в изучение электроники с нуля. О каких переключателях идёт речь? О мультиплексорах? Об обычных ключевых схемах? О выключателях света на стенах квартир? О чём?) Покажите схему и ткните пальцем с вопросом "что это?", так будет проще.
    Ответ написан
    Комментировать
  • Как в конвейерном 32bit процессоре передается команды записи в Reg 32 Битного значения??

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    А как передать-то 32 битное значение в команде в 32 бит?
    Логично что после команды значение(или адрес). Но тогда же получается какое-то нарушение логики.

    В RISC-процессорах -- никак. Они либо имеют команду загрузки 32-битного значения (литерала) из памяти относительно PC или специально выделенного регистра (например ARM: LDR r [pc, #offset_to_literal_pool], XTENSA: l32r at, label), при этом в команде кодируется смещение адреса литерала относительно PC. Либо загружают значения по частям, двумя или более командами (например MIPS загружает 16-битные части двумя разными инструкциями: lui rt, high16 ; ori rt, low16, XTENSA загружает 16-битные части двумя одинаковыми инструкциями: CONST16 at, high16 ; CONST16 at, low16, RISC-V загружает 20 и 12-битные части: auipc rd, symbol[31:12] ;addi rd, rd, symbol[11:0]).
    Хотя в принципе тот же RISC-V имеет нефиксированную длину команд, так, что какой-нибудь разработчик может завести, скажем, 6-байтовую команду загрузки 32-битного непосредственного значения в регистр, однако, насколько мне известно, никто этого не делает.
    Ответ написан
    Комментировать
  • Как вычисляется 20 битный адрес путем сложения 16 бит адреса сегмента с 16 бит смещением в процессорах Intel 8086?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Всё достаточно просто. У нас целый мегабайт памяти, нам надо 20 бит адреса, а регистры 16-битные.
    Для того, чтобы можно было оптимально выделять память, разобьём её на блоки по 220-16 = 16 байт. Пронумеруем эти блоки, получим 16-битные номера.
    Теперь для выделения фрагмента памяти мы можем взять номер первого выделяемого 16-байтного блока и количество блоков. Каждый такой выделенный фрагмент памяти назовём сегментом, а номер первого выделяемого блока - адресом сегмента. Внутри сегмента мы можем использовать 16-битную адресацию, что даёт размер сегмента в 64KB.
    Но оперативная память ничего не знает о сегментах, ей нужен 20-битный адрес. Поэтому мы берём адрес сегмента, умножаем его на размер блока (16 байт) и прибавляем адрес внутри сегмента.
    Ответ написан
    1 комментарий
  • Как с MathNet.Numerics уменьшить число коэффициентов у преобразования Фурье?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Игнорируй младшие коэффициенты - вот и будет сжатие. Так оно и работает. Честно-честно.
    Ответ написан
    4 комментария
  • Как с MathNet.Numerics уменьшить число коэффициентов у преобразования Фурье?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Быстрое преобразование Фурье - это алгоритм вычисления дискретного преобразования фурье. От интеграллов на картинках оно отличается тем, что там не функция от которой береться интеграл, а массив данных, которые как-то суммируются. Оно называется быстрым, потому что там идет вычисление не в лоб по формуле из википедии, а чуть хитрее, за счет чего оно работает быстрее.

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

    И да, там результат - это массив комплексных чисел, поэтому выходные данные в 2 раза больше входных, которые являются вещественными.
    Ответ написан
    3 комментария
  • С# Почему не сохраняется массив RGB пикселей? Image.Save System.ArgumentException: Parameter is not valid ????? КАК КОНВЕРТИРОВАТЬ?

    freeExec
    @freeExec
    Участник OpenStreetMap
    Он загружает в Image не массив пикселей, а стандартные форматы картинок (jpeg/png). Просто не из файла, а из памяти. Поэтому он всё знает и про размер и про битность.
    Ответ написан
    Комментировать
  • Как сделать размытие по гауссу изображения. Что на вход то поступает?

    mayton2019
    @mayton2019
    Bigdata Engineer
    На хабре есть статья посмотри https://habr.com/ru/post/142818/

    Ты всё в кучу смешал. При чем тут Фурье? Это совсем другое преобразование и смысл его другой.

    Где в этом уравнение передается информация про цвет или яркость, пикселя?

    Никакая яркость пикселя тебе не нужна. Фильтр применяется последовательно к каждому цветовому каналу отдельно. RGB, CMY рассматриваются как 3д поверхности где высота поверхности равна значению канала.
    Все вычисления лучше нормировать к диапазону вещественных чисел от 0 до 1 а когда все расчеты закончены - обратно приводить к RGB(8:8:8) например.

    В компьютерной графике есть понятие матричных фильтров. Это - самые простые фильтры в смысле ресурсов. И самые общие. Потому что любой фильтр отличается просто размером матрицы и коеффициентами.

    Конвейер такой.
    1) Определяешь размер матрицы (допустим 15 на 15)
    2) Инициализируешь матрицу по любой формуле. Например если все закрасить константой - то будет блур но не красивый с квадратрыми облаками в результате на картинке. Для гаусса - берешь эту формулу и подгоняешь чтобы в центре матрицы был максимум. Матрциа должна быть нормирована так чтобы в сумме не менять энергию всех пикселов которые попадают в квадрат 15 на 15. Подумай сам над этим. Гаусс также параметризуется средним квадратическим отклонением. Это скорее всего параметр сигма в формуле. Чем оно больше - тем размытее картинка. Но делать сигму больше чем 7.5 нет смысла при таком размере.

    2) Матрица применяется к каждому цветовому каналу изображения по принципу перемножисть каждое на каждое и сложить. Пиксели перемножаются на матрицу. Результат всего записывается в центральный пиксель. И так далее.

    3) На краях изображения будет баг. Потому что матрица вылезает за края. Картинки. Ты должен придумать как красить несуществующие пиксели. Можно красить в какой-то средний близкий цвет по расстоянию.

    4) Обычно матричный фильтр работает медленно. Есть оптимизации на низком уровне. В основном - перписывание на длинных командах типа SSE/AVX. И разбиение картинки на полоски с предварительным расчетом умножений. Но это работет для малых матриц. И надо учитывать влияние и размер кешей. Тоесть цифры которые будут получены на 1 конфигурации железа могут сильно отличатсья от другой.
    Ответ написан
    2 комментария
  • Как научные институты передают данные?

    dollar
    @dollar
    Делай добро и бросай его в воду.
    Если нет инета или он слабый, то возят жёсткие диски.
    Ответ написан
    Комментировать
  • Как научные институты передают данные?

    @Drno
    Возят диски. Фурой
    Ответ написан
    Комментировать