Пульсирующие записи к SD/USB, останавливающему мои строго ограниченные во времени приложения на встроенном Linux

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

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

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

13
задан blueshift 17 September 2008 в 14:01
поделиться

9 ответов

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

Большая победа прибыла из создания многопоточного приложения для устройства записи пространства пользователя. Это - вызовы для записи () что блок иногда: другие процессы и потоки все еще выполняются. Пока у меня есть поток, обслуживающий драйвер устройства и обновляющий количества кадра и другие данные к sychronise с другими приложениями, которые работают, данные могут быть буферизованы и выписаны несколько секунд спустя, не повреждая крайних сроков. Я попробовал простой двойной буфер пинг-понга сначала, но это не было достаточно; маленькие буферы были бы разбиты, и большие просто вызвали большие паузы, в то время как файловая система переварила записи. Пул 10 буферов 1 МБ, поставленных в очередь между потоками, работает хорошо теперь.

Другой аспект следит за окончательной пропускной способностью записи к физическим средам. Для этого я слежу за Грязной статистикой: сообщаемый/proc/meminfo. У меня есть некоторый грубый и готовый код для регулировки кодера если Грязный: подъемы выше определенного порога, кажется, неопределенно работает. Больше тестирования и настройки необходимы позже. К счастью, у меня есть много RAM (128M) для проигрывания с предоставлением мне нескольких секунд, чтобы видеть, что мое отставание растет и снижает скорость гладко.

Я попытаюсь не забыть появляться назад и обновлять этот ответ, если я найду, что должен сделать что-либо еще, чтобы заниматься этой проблемой. Благодаря другим отвечающим сторонам.

10
ответ дан 1 December 2019 в 22:08
поделиться

Я выведу некоторые предложения, совет является дешевым.

  • удостоверьтесь, что Вы используете более низкий уровень API для записи в диск, не используйте функции кэширования непривилегированного режима как fopen, fread, fwrite используйте более низкие функции уровня open, read, write.
  • передайте O_SYNC отметьте при открытии файла это заставит каждую операцию записи блокироваться, пока не записано в диск, который удалит пульсирующее поведение записей... с расходом каждой записи, являющейся медленнее.
  • При выполнении reads/ioctls от устройства для захвата блока видеоданных, можно хотеть рассмотреть выделение региона общей памяти между приложением и ядром, иначе Вы становитесь пораженными набором copy_to_user вызовы при передаче видеоданных буферизуют от пространства ядра до пространства пользователя.
  • Вы, возможно, должны проверить то свое устройство флэш-памяти USB, достаточно быстро с длительными передачами для записи данных.

Просто пара мыслей, надейтесь, что это помогает.

4
ответ дан 1 December 2019 в 22:08
поделиться

Кажется, что Вы ищете Linux файловые системы в реальном времени. Обязательно ищите Google и др. это.

XFS имеет опцию в реальном времени, хотя я не играл с ним.

hdparm мог бы позволить Вам выключить кэширование в целом.

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

Но мое предложение состояло бы в том, чтобы избегать использования палки как файловой системы вообще и вместо этого использовать ее в качестве неструктурированного устройства. Данные материала по нему как Вы были бы с помощью 'dd'. Затем в другом месте считайте, что необработанные данные и выписывают его после выпекания.

Конечно, я не знаю, является ли это опцией для Вас.

2
ответ дан 1 December 2019 в 22:08
поделиться

Вот некоторая информация о настройке pdflush для тяжелых записью операций.

3
ответ дан 1 December 2019 в 22:08
поделиться

Имеет помощь для отладки, Вы могли использовать strace для наблюдения, какие операции занимает время. Могла бы быть некоторая удивительная вещь с FAT/FAT32.

Вы пишете в единственный файл, или в нескольких регистрируют?

Можно сделать поток чтения, который поддержит пул видео буфера, готового быть записанным в очереди. Когда кадр принимается, он добавляется к очереди, и поток записи сообщен

Совместно используемые данные

empty_buffer_queue
ready_buffer_queue
video_data_ready_semaphore

Чтение потока:

buf=get_buffer()
bufer_to_write = buf_dequeue(empty_buffer_queue)
memcpy(bufer_to_write, buf)
buf_enqueue(bufer_to_write, ready_buffer_queue)
sem_post(video_data_ready_semaphore)

Запись потока

sem_wait(vido_data_ready_semaphore)
bufer_to_write = buf_dequeue(ready_buffer_queue)
write_buffer
buf_enqueue(bufer_to_write, empty_buffer_queue)

Если Ваша поточная запись заблокирована, ожидая ядра, это могло бы работать. Однако, если Вы заблокированы в пространстве kerne, затем thereis ничего особенного, что можно сделать, кроме поиска более свежего ядра, чем 2.6.10

1
ответ дан 1 December 2019 в 22:08
поделиться

Не зная больше о Ваших конкретных обстоятельствах, я могу только предложить следующие предположения:

Попытайтесь использовать fsync () / синхронизация (), чтобы вынудить ядро сбрасывать данные к устройству хранения более часто. Это кажется, что ядро буферизует все Ваши записи и затем связывает шину или иначе останавливает Вашу систему при выполнении фактической записи. С осторожными вызовами к fsync () можно попытаться запланировать, переписывает системную шину более мелкомодульным способом.

Могло бы иметь смысл структурировать приложение таким способом, которым кодированием/получением (Вы не упоминали видеосъемку, таким образом, я делаю предположение здесь - Вы могли бы хотеть добавить больше информации), выполнения задачи в ее собственном потоке, и буферизует ее вывод в пространстве пользователя - затем, второй поток может обработать запись в устройство. Это даст Вам буфер сглаживания, чтобы позволить кодеру всегда заканчивать свои записи без блокирования.

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

В любом случае больше информации могло бы оказаться полезным. Какова архитектура Вашей системы? (В самых общих чертах.)

Учитывая дополнительную информацию Вы, если, это походит на пропускную способность устройства, довольно бедны для маленьких записей и частых сбросов. Если Вы уверены, что для больших записей можно получить достаточную пропускную способность (и я не уверен, что это имеет место, но файловая система могла бы делать что-то глупое, как обновление FAT после каждой записи), затем наличие данных передачи по каналу потока кодирования к записи распараллеливает с достаточной буферизацией в потоке записи для предотвращения остановов. Я использовал кольцевые буферы общей памяти в прошлом для реализации этого вида схемы, но любой механизм IPC, который позволил бы устройству записи писать в процесс ввода-вывода, не останавливаясь, если буфер не полон, должен добиться цели.

1
ответ дан 1 December 2019 в 22:08
поделиться

Полезная функция Linux и альтернатива синхронизации или fsync являются sync_file_range. Это позволяет Вам запланировать данные для записи, не ожидая буферной системы в ядре для возвращения для него.

Для предотвращения длинных пауз удостоверьтесь очередь IO (например:/sys/block/hda/queue/nr_requests), является достаточно большим. Та очередь - то, куда данные идут промежуточные сбрасываемый из памяти и прибывающий в диск.

Обратите внимание, что sync_file_range не является портативным, и является только доступным в ядрах 2.6.17 и позже.

1
ответ дан 1 December 2019 в 22:08
поделиться

Хорошо очевидный первый, Вы попытались явно говорить файлу сбрасывать? Я также думаю, что мог бы быть некоторый ioctl, который можно использовать, чтобы сделать это, но я честно не сделал большого программирования файла C/POSIX.

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


Быстрая проверка в моих страницах справочника находит это:

SYNC(2)                    Linux Programmer’s Manual                   SYNC(2)

NAME
       sync - commit buffer cache to disk

SYNOPSIS
       #include <unistd.h>

       void sync(void);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       sync(): _BSD_SOURCE || _XOPEN_SOURCE >= 500

DESCRIPTION
       sync() first commits inodes to buffers, and then buffers to disk.

ERRORS
       This function is always successful.
0
ответ дан 1 December 2019 в 22:08
поделиться

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

Это может быть очевидно, но удостовериться, что Вы не звоните, запись () слишком часто - удостоверяются, что каждая запись () имеет достаточно данных, которые будут записаны для создания syscall служебным стоящий того. Кроме того, в другом направлении не называйте его слишком редко, или это заблокируется довольно долго для порождения проблемы.

На большем количестве дорожки difficult-to-reimplement Вы попытались переключиться на асинхронный i/o? Используя aio Вы могли исчерпать запись и вручить ему один набор буферов при всасывании видеоданных в другой набор, и когда запись заканчивает Вас наборы переключателя буферов.

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

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