LINUX.ORG.RU

Фрагментации памяти тред.

 ,


0

4

Ночи доброй, ЛОР. Давно на жабе уже пишу, а задумался об этом только сейчас, но, скорее всего, это и к другим языкам относится. Вот есть у нас List<T>, у него есть 2 реализации, LinkedList и ArrayList. Насколько я помню ещё из С, мы можем производить т.н. арифметику указателей в случае с массивом (ArrayList), т.е. память под него выделяется одним куском, в то время как LinkedList, насколько я понимаю, может быть раскидан по всему адресному пространству, просто каждая нода содержит указатель на next, если таковой имеется. Главный вопрос: Правильно ли я понимаю, что в ситуации, когда у нас доступно, допустим, 8 кб памяти и мы пытаемся создать List с данными на 6 - мы можем вывалиться в ООМ в случае с ArrayList из-за фрагментации этой самой памяти? И верно ли утверждение, что в случае с LinkedList такого не произойдет, потому что ему на фрагментацию положить? Заранее спасибо.
/cast stevejobs

★★★★

Для «других языков» это может быть верно, но в Яве автоматическая компкатификация кучи.

tailgunner ★★★★★
()

Я не знаю, как себя ведет Java при недостатке памяти, по простой причине: на веб-сервисах никогда не должно быть недостатка памяти. И своп тоже использовать нельзя. Только настоящая память, действительно существующая, с избытком.

stevejobs ★★★★☆
()

в случае с массивом (ArrayList), т.е. память под него выделяется одним куском

нет. Только массив референсов на объекты будет примерно одним куском. А сами элементы будут лежать как попало в куче. И когда по ним пройдется сборщик мусора и что-нибудь куда-нибудь переместит, будет совсем как попало.

Плюс, когда ArrayList полностью заполнен, он создает новое хранилище для референсов на свои объекты размером "(текущий_размер * 3/2) + 1", после чего старые референсы копируются в это новое хранилище

то что ты хочешь (последовательный кусок) сейчас делается в проекте Valhalla, называется Value Types. Существует демка за прошлую осень, но пока она дойдет до прода - может пройти несколько лет

stevejobs ★★★★☆
()

Обычно если не хватает памяти, вызывается GC, а NPE кидается, если даже после GC её всё равно не хватает. Популярные GC дефраментируют память, поэтому такая проблема маловероятна. На самом деле очень мало причин использовать LinkedList и очень много причин использовать ArrayList, поэтому настоятельно рекомендую использовать последний по умолчанию в подавляющем большинстве случаев.

Legioner ★★★★★
()
Ответ на: комментарий от stevejobs

Только массив референсов на объекты будет примерно одним куском

Эвано как. Об этом не догадывался. А ноды LinkedList'a тоже по факту содержат не объекты, а указатели на область в куче?

Jefail ★★★★
() автор топика
Ответ на: комментарий от Legioner

и это проблема! (которую сейчас решают в Valhalla). В доступной демке, можно поставить аннотацию @DVT над «структурой», и ждк попробует разлинеить память

stevejobs ★★★★☆
()
Ответ на: комментарий от stevejobs

А потом они добавят сырые указатели, прямой доступ к памяти и ручное управление аллокациями и деаллокациями. И получится C++.

i-rinat ★★★★★
()

И верно ли утверждение, что в случае с LinkedList такого не произойдет, потому что ему на фрагментацию положить?

В общем случае нет (для языков без GC):

+-------------+-------------+-------------+
|             |  Old        |             |
|   5 KiB     |  Linked     |    5 KiB    |
|             |  List       |             |
+-------------+-------------+-------------+
и чтобы добавить элемент надо сначала выделить новую память в 8 KiB, чтобы в неё копировать из старой. А выделить может не получиться.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Всё же всё это вкусовщина. У Java, учитывая static, default и private methods, получается что-то подобное, правда с некоторыми ограничениями.

Хотя у меня лишь один раз возникало желание реализовать что-то в private method'е.

Deleted
()
Ответ на: комментарий от Jefail

вот картинки такие видел ещё давно, но в тему

auto car_list() {
  auto n = 7;
  auto cars = std::vector<Car>{};
  cars.reserve(n);
  for(auto i=0; i<n; ++i){
    cars.push_back(Car{});
  }
}
https://www.packtpub.com/graphics/9781787120952/graphics/37519818-633e-4c83-b...

void carList() {
  int n = 7;
  ArrayList<Car> cars = 
    new ArrayList<Car>();
  for(int i=0; i<n; i++) {
    cars.addElement(new Car());
  }
}

https://www.packtpub.com/graphics/9781787120952/graphics/35e0bacc-dfbe-43aa-9...

так же там текст был

The C++ vector contains the actual Car objects placed in one contiguous memory block, whereas the equivalent in Java is a contiguous memory block of references to Car objects. In Java, the objects has been allocated separately, which means that they can be located anywhere in the heap.
This affects the performance as Java has to execute seven allocations instead of one. It also means that whenever the application iterates the list, there is a performance win for C++, since accessing nearby memory locations is faster than accessing several random spots in memory.

fsb4000 ★★★★★
()
Ответ на: комментарий от Jefail

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

tyamur ★★
()
Ответ на: комментарий от i-rinat

не дождетесь )))

олсо, прямой доступ к памяти не означает, что это будет доступно из пользовательского API

сейчас например, предлагается убрать аннотацию «value type». Пусть JVM сама решает, что есть VT, а что - нет

stevejobs ★★★★☆
()

Жабка же ЯП с GC, там все объекты доступны только по ссылке, в контейнерах соответственно хранятся ссылки на объекты, а не значения. Поэтому массив от связанного списка по идее ничем отличаться не должен.

Virtuos86 ★★★★★
()
Ответ на: комментарий от anonymous

А что такое «прямой доступ к памяти» в C++?

Это возможность любое число преобразовать в указатель, а потом указатель разыменовать.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Это возможность любое число преобразовать в указатель, а потом указатель разыменовать.

Что, стандарт разрешает такое?

anonymous
()
Ответ на: комментарий от anonymous

а подумать? атмежный spi control register лежит по адресу 0x2c. как ты ещё получишь к нему доступ кроме как через (my_focking_spi_control_register *)0x2c например? а, гений программирования? давай расскажи нам.

anonymous
()
Ответ на: комментарий от anonymous

Можно подробнее?

#include <string.h>

int main() {
  void *data_ptr = reinterpret_cast<void *>(0xffffffffff600000);
  size_t data;
  memcpy(&data, data_ptr, sizeof(data)); // ← Разыменование через memcpy.

  printf("%zx\n", data);
}
i-rinat ★★★★★
()
Ответ на: комментарий от anonymous

Я читал что integer можно кастовать в pointer, если этот integer был до этого получен из pointer.

Что-то не видел такого. Тогда как насчёт такого?

char *ptr = nullptr;
ptr += 0xffffffffff600000;
i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Тогда как насчёт такого?

http://eel.is/c++draft/expr.add#4

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x of an array object x with n elements, the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i+j] if 0≤i+j≤n; otherwise, the behavior is undefined. Likewise, the expression P - J points to the (possibly-hypothetical) element x[i−j] if 0≤i−j≤n; otherwise, the behavior is undefined.

nullptr не указывает на элемент массива.

anonymous
()
Ответ на: комментарий от anonymous
if (p.points_to_array_object()) {
  if (p.inside(0, n) {
    return ok();
  }
}

return undefined();

vs.

if (p.points_to_array_object()) {
  if (p.inside(0, n) {
    return ok();
  } else {
    return undefined();
  }
}
// may return ok() somewhere else
i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

http://eel.is/c++draft/expr.add#footnote-86.sentence-1

An object that is not an array element is considered to belong to a single-element array for this purpose

This purpose == арифметика указателей.

Любой указатель при арифметике указателей считается указателем на элемент массива. Ну или получается UB, если он не указывает на элемент массива (или отдельный объект, воспринимаемый как элемент одноэлементного массива).

anonymous
()
Ответ на: комментарий от anonymous

Любой указатель при арифметике указателей считается указателем на элемент массива.

s/считается/должен быть/

anonymous
()
Ответ на: комментарий от foror

думаю еще года два ) Наличие демок не значит, что это можно тащить в прод. А там очень сложные проблемы, требуют сильного перехерачивания JVM с перетестированием всего на свете

stevejobs ★★★★☆
()

Правильно ли я понимаю, что в ситуации, когда у нас доступно, допустим, 8 кб памяти и мы пытаемся создать List с данными на 6 - мы можем вывалиться в ООМ в случае с ArrayList из-за фрагментации этой самой памяти?

Нет, т.к. жаба не обязана хранить объекты твоего списка одним куском.

ya-betmen ★★★★★
()
Ответ на: комментарий от stevejobs

думаю еще года два

джва года ждём!

anonymous
()
Ответ на: комментарий от i-rinat

А потом они добавят сырые указатели, прямой доступ к памяти и ручное управление аллокациями и деаллокациями. И получится C++.

не, сначала получится C#.. там это есть :)

waker ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.