Об управлении памятью в Java и C++

Часть map преобразования / уменьшения преобразует (отображает) каждую входную запись в пару (ключ -> значение).

Входная запись -> x Функция карты -> f Вывод функции карты на входную запись -> f(x)

В вашем конкретном примере это преобразование кортежа {userID, movieID , отметка времени} для сопоставления значения ключа (movieId -> userId) путем сброса отметки времени.

Часть reduce карты / уменьшения берет каждое отображение значения ключа, которое вы создали из вышеупомянутого, и выполняет функцию агрегирования (уменьшения). Поскольку все данные для одного key должны быть расположены на одном узле, чтобы выполнить точное вычисление агрегации, значения для конкретного key перемещаются на конкретный узел, который отвечает за это key. Вот почему reduce принимает ввод как (клавиша -> Список (значение)) или для вашего примера (movieId -> Список (userIds)). Так что да, для каждого вызова reduce, key будет отличаться.

Вывод функции reduce будет уникальным (ключ -> aggregation_computation (значения)) для каждой клавиши ввода. Например, в вашем случае

Movie (Id)              Number of Users
Star Wars               50
John Wick               32
Fifty Shades of Grey    9000
...
8
задан Bill the Lizard 18 September 2012 в 14:14
поделиться

2 ответа

Какова точно была задача, которую Вам дали?

Основное различие между Java и C++ - то, что Java собран "мусор" VM, тогда как в C++ программа непосредственно выполняется на машине, и памятью управляют через службы ОС.

Относительно стека кадр является просто более "официальной" и стандартной формой того, что делают компиляторы C++. Компиляторы C++ просто помещают вещи друг на друге в стек, когда Вы перемещаетесь от "вызова к вызову". В Java термин является кадром, и потому что скомпилированный код Java, как предполагается, работает на любой платформе, существуют очень четкие стандарты о том, как это происходит. В C++ каждый компилятор может рассматривать стек по-другому (например, даже по природе размера слова).

В Java все работает в VM, который управляет всем, хотя он делегирует некоторый материал к среде. Другими словами, у Вас нет доступа туда, где JVM помещает Ваши данные и Ваш код, и Ваш код может даже не стать реальным "сегментом кода". Другими словами, этому нельзя действительно ответить. В C++ все работает над аппаратными средствами, таким образом, у Вас будут сегменты стека, сегменты данных, и т.д. Посмотрите в информации о C++.

В C++ классы не имеют никакого представления в памяти во времени выполнения; на самом деле можно скомпилировать C++ в C и затем скомпилировать результаты в блок. В Java все также представлено во времени выполнения, таким образом, можно спросить объект, какому классу это принадлежит и какой метод является поддержками. Следовательно, каждый файл класса имеет "постоянный пул", где строки, представляющие те вещи как имена методов, имена полей, и т.д. появляются. Фактическое определение класса относится к пулу. Так, другими словами, это очень мало имеет отношение к стековым фреймам. Стековые фреймы - то, где параметры метода, локальные переменные и возвращаемые значения хранятся.

3
ответ дан 5 December 2019 в 19:03
поделиться

Смотря на структуру спецификации JVM, это в основном говорит, что стек содержит кадры, и что кадры содержат то, что в классе путем надлежащего выделения переменных и функций. Возможно, я пропускаю что-то здесь, но я не понимаю, как это несколько отличается, чем, что делает C++. Я спрашиваю, потому что в первой ссылке говорится, что спецификация Java содержания стека избегает несовместимостей компилятора.

На практике компиляторы C++ следуют той же основной стратегии. Однако это не рассмотрело выпуск языка комитетом по Стандартам. Вместо этого компиляторы C++ следуют за этой системой, потому что это - то, как разработаны большинство центральных процессоров и операционных систем. Различные платформы не соглашаются относительно того, передаются ли данные функциям на стеке или через регистры (машины RISC), растет ли стек или вниз, существуют ли различные соглашения о вызовах, позволяющие "нормальные" вызовы использовать стек и других еще для использования чего-то (например, __ fastcall и явный), таково ли там как вещь как вложенные функции, поддержка последнего вызова, и т.д.

На самом деле для соответствующего компилятора C++ возможно скомпилировать во что-то как Схема VM, где "стек" очень отличается, потому что Схема требует реализаций к обращениям за поддержкой и последние вызовы и продолжения. Я никогда не видел ничего как этот, но это было бы законно.

"Несовместимости компилятора" являются самыми очевидными, при попытке записать сборщик "мусора":

все локальные переменные, и для текущей функции и для всех ее вызывающих сторон, находятся в [стек, но рассматривают ucontext.h и Windows Fibers]. Для каждой платформы (значение, ОС + ЦП + компилятор) существует способ узнать, где [стек]. Игрунок делает это, затем он сканирует всю эту память во время GC для наблюдения, где местные жители указывают на...

Это волшебство живет в макросе, MMGC_GET_STACK_EXTENTS, определенном в заголовке MMgc/GC.h.... [T] вот отдельная реализация для каждой платформы.

В любой данный момент некоторые местные жители могли бы быть в регистрах ЦП а не на стеке. Для преодоления этого макрос использует несколько строк ассемблерного кода для дампа содержания всех регистров на стек. Тем путем MMgc может просто просканировать стек, и он будет видеть все локальные переменные.


Кроме того, объекты в Java обычно не выделяются на стеке. Вместо этого ссылки на них. ints, удваивается, булевские переменные, и другие типы примитивов действительно становятся выделенными на стеке. В C++ что-либо может быть выделено на стеке, который имеет его собственный список за и против.

Другой вещь, которую я не понимаю, является пулом константы этапа выполнения. Это, как предполагается, "представление во время выполнения на интерфейс или на класс constant_pool таблицы в файле класса", но я не думаю, что понимаю то, что это делает.

Рассмотрите:

String s = "Hello World";
int i = "Hello World".length();
int j = 5;

s, я и j - все переменные и можем каждый быть изменены в некоторой более поздней точке в программе. Однако "Привет Мир" является объектом Струны типа, которая не может поменяться, 5 интервал, который не может быть изменен, и "Привет Мир" .length () может быть полон решимости во время компиляции всегда возвратиться 11. Эти константы являются доступными объектами, и методы можно назвать на них (хорошо, по крайней мере, на Строке), таким образом, они должны быть выделены где-нибудь. Но они не могут быть изменены, никогда. Если эти константы принадлежат классу, то они выделяются в постоянном пуле на класс. Другие постоянные данные, которые не являются частью класса (как идентификатор основного () поток) выделяются в пуле на константу этапа выполнения ("время выполнения" в этом случае, означающем "экземпляр JVM").

Стандарт C++ имеет некоторый язык о подобной технике, но реализацию оставляют до двоичного формата (ELF, a.out, COFF, PE, и т.д.). Стандарт ожидает константы, которые являются интегральными типами данных (bool, интервал, долго, и т.д.) или строки c-стиля, которые будут на самом деле сохранены в постоянной части двоичного файла, в то время как другие постоянные данные (удваивается, плавания, классы) могли бы храниться как переменная наряду с флагом, говоря, что "переменная" не является модифицируемой (также приемлемо снабдить их интегралом и строковыми константами c-стиля, но много двоичных форматов не делают это опцией).

Вообще говоря, "постоянный раздел данных" двоичного файла может быть совместно использован, когда больше чем одна копия программы открыта за один раз (потому что постоянные данные будут идентичны в каждой копии программы). На ELF этот раздел называют разделом .rodata.

6
ответ дан 5 December 2019 в 19:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: