Как избежать фрагментации кучи?

Короткий ответ:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

Объяснение: (на основе этот вопрос о LocalDate)

Несмотря на свое имя, java.util.Date представляет мгновение на линии времени, а не «дата». Фактические данные, хранящиеся в объекте, представляют собой long счет миллисекунд с 1970-01-01T00: 00Z (полночь в начале 1970 GMT / UTC).

Эквивалентный класс для java.util.Date в JSR-310 является Instant, поэтому есть удобные способы для обеспечения преобразования в:

Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);

Экземпляр java.util.Date не имеет понятия о временной зоне. Это может показаться странным, если вы назове toString() на java.util.Date, потому что toString относится к временной зоне. Однако этот метод фактически использует временную зону Java по умолчанию для предоставления строки. Часовой пояс не является частью фактического состояния java.util.Date.

Instant также не содержит никакой информации о временной зоне. Таким образом, для преобразования из Instant в локальную дату-время необходимо указать временную зону. Это может быть зона по умолчанию - ZoneId.systemDefault() - или это может быть временная зона, которую контролирует ваше приложение, например часовая зона от пользовательских настроек. LocalDateTime имеет удобный заводский метод, который принимает как мгновенную, так и временную зону:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());

В обратном порядке LocalDateTime зона времени задается вызовом метода atZone(ZoneId). Затем ZonedDateTime можно преобразовать непосредственно в Instant:

LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());

Обратите внимание, что преобразование с LocalDateTime в ZonedDateTime может привести к неожиданному поведению. Это связано с тем, что не всегда существует локальная дата-время из-за летнего времени. Осенью / осенью в локальной временной линии происходит перекрытие, где одно и то же локальное время-дата происходит дважды. Весной есть пробел, где час исчезает. См. Javadoc из atZone(ZoneId) для более подробного определения того, что будет делать преобразование.

Сводка, если вы совершите кругооборот java.util.Date до LocalDateTime и обратно к java.util.Date вы можете получить другой момент из-за перехода на летнее время.

Дополнительная информация: Существует еще одна разница, которая повлияет на очень старые даты. java.util.Date использует календарь, который имеет шансы 15 октября 1582 года, с датами до этого с использованием юлианского календаря вместо григорианского. Напротив, java.time.* использует систему календаря ISO (эквивалентно григорианскому) на все время. В большинстве случаев система календаря ISO - это то, что вы хотите, но вы можете видеть нечетные эффекты при сравнении дат до 1582 года.

13
задан Suma 29 September 2009 в 19:08
поделиться

9 ответов

При выполнении медицинской обработки изображений, вероятно, что Вы выделяете большие блоки за один раз (512x512, изображения на 2 байта на пиксель). Фрагментация укусит Вас при выделении меньших объектов между выделения буферов изображения.

Запись пользовательского средства выделения не обязательно трудна для этого конкретного примера использования. Можно использовать стандартное средство выделения C++ для Объекта изображения, но для пиксельного буфера можно использовать пользовательское выделение, которое все организовано в Объекте изображения. Вот быстрая и грязная схема:

  • Использование статический массив структур, каждая структура имеет:
    • блок тела А памяти, которая может содержать изображения N - разделение на блоки, поможет управлять фрагментацией - пробуют начальную букву N приблизительно 5
    • массив параллели А указания bools, используется ли соответствующее изображение
  • , Чтобы выделить, искать массив пустой буфер и установить его флаг
    • , Если ни одно найденное, добавьте новую структуру в конец массива
  • Для освобождения, найдите соответствующий буфер в массиве (массивах) и очистите булев флаг

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

15
ответ дан Jeff Kotula 30 September 2009 в 06:08
поделиться

Без намного большей информации о проблеме (например, язык), одна вещь, которую можно сделать, состоит в том, чтобы избежать маслобойки выделения путем многократного использования выделений и не выделить, работать и свободный. Средство выделения такой как dlmalloc обрабатывает фрагментацию лучше, чем "куча" Win32.

2
ответ дан Torlack 30 September 2009 в 06:08
поделиться

Если Вы собираетесь быть операциями выполнения на большой матрице изображений, Вы могли бы хотеть полагать, что техника назвала "мозаичное размещение". Идея состоит в том, чтобы обычно загружать изображение в памяти так, чтобы тот же непрерывный блок байтов не содержал бы пиксели в одной строке, а скорее квадрата в 2D пространстве. Объяснение позади этого - то, что Вы сделали бы больше операций, которые ближе друг к другу в 2D, а не на одной строке развертки.

Это не собирается уменьшать Ваше использование памяти, но может оказать огромное влияние на свопинг страницы и производительность.

5
ответ дан Uri 30 September 2009 в 06:08
поделиться

Существуют ответы, но трудно быть общим, не зная детали проблемы.

я принимаю 32-разрядный Windows XP.

Стараются не требоваться 100 с МБ непрерывной памяти, если Вы будете неудачны, то несколько случайных dlls загрузят себя в точках inconventient через Ваше доступное адресное пространство, быстро сокращающее очень большие площади непрерывной памяти. В зависимости от того, в каких API Вы нуждаетесь, это может быть довольно трудно предотвратить. Может быть довольно удивительно, как просто выделение нескольких блоков 400 МБ памяти в дополнение к некоторому 'нормальному' использованию памяти может оставить Вас с нигде не выделить заключительный 'небольшой' блок 40 МБ.

, С другой стороны, действительно предварительно выделите разумные блоки размера за один раз. Из порядка приблизительно 10 МБ хороший размер блока компромисса. Если можно удаться разделить данные в этот вид блоков размера, Вы сможете заполнить адресное пространство обоснованно эффективно.

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

Выбор, где разбить на страницы вещи к, является другим решением. Вы могли бы решить просто записать им во временные файлы. Вы могли также исследовать Работу с окнами Адреса Microsoft Extenstions API. В любом случае необходимо быть осторожными в проектировании приложений для чистки любых указателей, которые указывают на что-то, что собирается быть разбитым на страницы, иначе действительно плохие вещи (TM) произойдут.

Удачи!

5
ответ дан CB Bailey 30 September 2009 в 06:08
поделиться

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

Для C/C++ можно использовать некоторое другое средство выделения, чем по умолчанию. (были alrady некоторые потоки о средствах выделения на stackowerflow).

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

1
ответ дан Kasprzol 30 September 2009 в 06:08
поделиться

Предположение здесь, что Вы имели в виду , избегает, чтобы фрагментация а не избежала дефрагментации . Также предположение, что Вы работаете с не управляемым языком (c или C++, вероятно). Я предложил бы, чтобы Вы выделили большие блоки памяти и затем служили выделениям "кучи" от выделенных блоков памяти. Этот пул памяти, потому что содержит большие блоки памяти, lessely подверженный фрагментации. Подвести итог Вас должно реализовать пользовательское средство выделения памяти.

Посмотрите некоторые общие представления на этом здесь .

1
ответ дан Jorge Ferreira 30 September 2009 в 06:08
поделиться

Вы, возможно, должны были бы реализовать ручное управление памятью. Действительно ли данные изображения долговечны? В противном случае затем можно использовать шаблон, используемый апачским веб-сервером: выделите большие объемы памяти и перенесите их в пулы памяти. Передайте те пулы как последний аргумент в функциях, таким образом, они могут использовать пул для удовлетворения потребности выделить временную память. После того как цепочка вызовов закончена, вся память в банке пула больше не должна использоваться, таким образом, Вы можете вычистить область памяти и использовали ее снова. Выделения быстры, так как они только означают добавлять значение к указателю. Освобождение действительно быстро, так как Вы освободите очень большие блоки памяти сразу.

, Если Ваше приложение является многопоточным, Вы, возможно, должны были бы сохранить пул в локальной памяти потока, избежать коммуникации перекрестного потока наверху.

1
ответ дан florin 30 September 2009 в 06:08
поделиться

Что Вы будете поражать, вот предел диапазона виртуальных адресов, который с 32b Windows дает Вам самое большее 2 ГБ. Необходимо также знать, что использование графического API как DirectX или OpenGL будет использовать обширные части тех 2 ГБ для кадрового буфера, структур и подобных данных.

1.5-2 ГБ для 32b приложения довольно трудно достигнуть. Самый изящный способ сделать это должно использовать 64b ОС и 64b приложение. Даже с 64b ОС и 32b приложение это может быть несколько жизнеспособно, пока Вы используете LARGE_ADDRESS_AWARE.

Однако, поскольку необходимо сохранить данные изображения, можно также смочь работать вокруг этого при помощи Файл, Отображающийся как хранилище памяти - это может быть сделано таким способом, которым Вам фиксировали память и доступный, но не использующий виртуальных адресов вообще.

2
ответ дан Suma 30 September 2009 в 06:08
поделиться

Если вы можете изолировать именно те места, где вы, вероятно, будете выделять большие блоки, вы можете (в Windows) напрямую вызвать VirtualAlloc вместо просмотра памяти менеджер. Это позволит избежать фрагментации в обычном диспетчере памяти.

Это простое решение, не требующее использования специального диспетчера памяти.

0
ответ дан 1 December 2019 в 19:51
поделиться
Другие вопросы по тегам:

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