Программа только отказывает как сборка конечных версий — как отладить?

Что такое 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 ).

88
задан Community 23 May 2017 в 11:33
поделиться

20 ответов

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

118
ответ дан James Curran 24 November 2019 в 07:27
поделиться

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

-6
ответ дан wnoise 24 November 2019 в 07:27
поделиться

Заставьте свою программу генерировать мини-дамп, когда исключение происходит, затем откройте его в отладчике (например, в WinDbg). Ключ функционирует для взгляда на: MiniDumpWriteDump, SetUnhandledExceptionFilter

0
ответ дан mikhailitsky 24 November 2019 в 07:27
поделиться

Вы могли бы запустить свое программное обеспечение с Глобальными включенными Флагами (Взгляд в Средствах отладки для Windows). Это будет очень часто помогать закрепить проблему.

0
ответ дан Marcin Gil 24 November 2019 в 07:27
поделиться

Попытайтесь использовать _CrtCheckMemory () для наблюдения то, что указывает, что выделенная память находится в. Если все подходит, возвраты _CrtCheckMemory TRUE, еще ЛОЖЬ .

0
ответ дан Vhaerun 24 November 2019 в 07:27
поделиться

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

Одна техника, чтобы, по крайней мере, сузить проблему должна использовать MessageBox () для отображения быстрых операторов, указывающих, какую часть программы код имеет к ("Стартовое Нечто ()", "Запуская Foo2 ()"); начните помещать их во главе функций в области Вашего кода, что Вы подозреваете (что Вы делали в то время, когда это отказало?). Когда можно сказать, который функция, измените окна сообщения на блоки кода или даже отдельные строки в той функции, пока Вы не сужаете его к нескольким строкам. Тогда можно начать распечатывать значение переменных для наблюдения то, что указывает, что они находятся в при катастрофическом отказе.

0
ответ дан 24 November 2019 в 07:27
поделиться

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

0
ответ дан Nick 24 November 2019 в 07:27
поделиться

Я нашел этот эта статья полезный для Вашего сценария. ISTR параметры компилятора немного устарели. Осмотрите свои опции проекта Visual Studio видеть, как генерировать pdb файлы для Вашей сборки конечных версий, и т.д.

0
ответ дан fizzer 24 November 2019 в 07:27
поделиться

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

ну, чтобы говорить правду это был мой отказ, не gcc's, поскольку я не сделал замеченный, что мой код полагался на то, что та конкретная оптимизация не будет сделана.

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

0
ответ дан Remo.D 24 November 2019 в 07:27
поделиться

Относительно Ваших проблем, получающих диагностическую информацию, Вы попытались использовать adplus.vbs в качестве альтернативы WinDbg.exe? Для присоединения к рабочему процессу используйте

adplus.vbs -crash -p <process_id>

Или запускать приложение, если катастрофический отказ происходит быстро:

adplus.vbs -crash -sc your_app.exe

Полная информация о adplus.vbs может быть найдена в: http://support.microsoft.com/kb/286350

1
ответ дан DocMax 24 November 2019 в 07:27
поделиться

Ntdll.dll с отладчиком присоединил

Один, мало знают различие между запуском программы от IDE или WinDbg в противоположность запуску его из командной строки / рабочий стол - то, что при запуске с присоединенным отладчиком (т.е. IDE или WinDbg) ntdll.dll использует различную реализацию "кучи", которая выполняет некоторую небольшую проверку на выделении памяти / освобождение.

можно считать немного релевантной информации в неожиданная пользовательская точка останова в ntdll.dll . Один инструмент, который мог бы быть в состоянии помочь Вам определяющий проблему, PageHeap.exe .

анализ Катастрофического отказа

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

1
ответ дан Community 24 November 2019 в 07:27
поделиться

, Как только у меня была проблема, когда приложение вело себя так же к Вашему. Это оказалось противным переполнением буфера в sprintf. Естественно, это работало, когда выполнено с присоединенным отладчиком. То, что я сделал, должно было установить фильтр необработанного исключения ( SetUnhandledExceptionFilter), в котором я просто заблокировался бесконечно (использующий WaitForSingleObject на поддельном дескрипторе со значением тайм-аута БОГА).

, Таким образом, Вы могли что-то вроде:

long __stdcall MyFilter(EXCEPTION_POINTERS *)
{
    HANDLE hEvt=::CreateEventW(0,1,0,0);
    if(hEvt)
    {
        if(WAIT_FAILED==::WaitForSingleObject(hEvt, INFINITE))
        {
            //log failure
        }
    }

}
// somewhere in your wmain/WinMain:
SetUnhandledExceptionFilter(MyFilter);

я тогда присоединил отладчик после того, как ошибка проявилась (gui, программа прекратила отвечать).

Тогда можно или взять дамп и работать с ним позже:

.dump / мама path_to_dump_file

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

Диапазон s-d esp 1003f

Команда будет искать, адресное пространство стека для записи (записей) КОНТЕКСТА обеспечило продолжительность поиска. Я обычно использую что-то как [1 111] 'l? 10000' . Отметьте, не используйте unsually большие количества в качестве записи, которая Вы после обычно близко к отпущенному кадру фильтра исключения. 1003f комбинация флагов (я полагаю, что она соответствует CONTEXT_FULL), раньше получал состояние процессора. Ваш поиск выглядел бы подобным этому:

0:000> s-d esp l1000 1003f
0012c160 0001003f 00000000 00000000 00000000?...............

, Как только Вы возвращаете результаты, используйте адрес в команде cxr:

.cxr 0012c160

Это возьмет Вас к этому новому КОНТЕКСТУ, точно во время катастрофического отказа (Вы получите точно отслеживание стека в то время свое разрушенное приложение). Кроме того, используйте:

.exr-1

для обнаружения точно, какое исключение произошло.

Hope это помогает.

2
ответ дан deemok 24 November 2019 в 07:27
поделиться

Для имения дампа катастрофического отказа, который можно проанализировать:

  1. Генерируют pdb файлы для Вашего кода.
  2. Вы повторно базируетесь для имения exe и dlls, загруженного в том же адресе.
  3. Включают отладчик после смерти такой как доктор Watson
  4. Проверка адрес отказов катастрофического отказа с помощью инструмента такой в качестве средство поиска катастрофического отказа .

необходимо также проверить инструменты в Средства отладки для окон . Можно контролировать приложение и видеть все первые случайные исключения, которые были до второго случайного исключения.

Hope это помогает...

3
ответ дан Yuval Peled 24 November 2019 в 07:27
поделиться

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

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

3
ответ дан Cruachan 24 November 2019 в 07:27
поделиться

Даже при том, что Вы создали свой exe как выпуск один, можно все еще генерировать PDB (База данных Program) файлы, которые позволят Вам отслеживанию стека и сделают ограниченный объем переменного контроля. В Ваших настройках сборки существует опция создать файлы PDB. Включите это и перессылку. Тогда попытайтесь работать от IDE сначала, чтобы видеть, получаете ли Вы катастрофический отказ. Если так, тогда большой - Вы все установлены посмотреть на вещи. В противном случае тогда при выполнении из командной строки можно сделать одну из двух вещей:

  1. EXE Выполнения, и перед катастрофическим отказом делают Присоединение К Процессу (Меню Tools на Visual Studio).
  2. После катастрофического отказа, выберите опцию запустить отладчик.

, Когда спросили указать на файлы PDB, обзор для нахождения их. Если PDB's был помещен в ту же выходную папку как Ваш EXE или DLL, они будут, вероятно, взяты автоматически.

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

нбар: я принимаю среду Windows/Visual Studio здесь.

7
ответ дан Greg Whitfield 24 November 2019 в 07:27
поделиться

После многих часов отладки я наконец нашел причину проблемы, которая была действительно вызвана переполнением буфера, вызвал единственное различие в байте:

char *end = static_cast<char*>(attr->data) + attr->dataSize;

Это - ошибка на единицу при счете (ошибка диапазона) и было зафиксировано:

char *end = static_cast<char*>(attr->data) + attr->dataSize - 1;

странная вещь была, я поместил несколько вызовов в _CrtCheckMemory () вокруг различных частей моего кода, и они всегда возвращались 1. Я смог найти, что источник проблемы размещением "возвращает false"; вызовы в тестовом сценарии, и затем в конечном счете определение методом проб и ошибок, где отказ был.

Спасибо все для Ваших комментариев - я узнал много о windbg.exe сегодня!:)

9
ответ дан Nik Reiman 24 November 2019 в 07:27
поделиться

Можно установить WinDbg как посмертный отладчик. Это запустит отладчик и присоединит его к процессу, когда катастрофический отказ произойдет. Для установки WinDbg для посмертной отладки используйте/I опцию (обратите внимание, что это , использовал для своей выгоды ):

windbg /I
[еще 113] детали здесь .

относительно причины, это - по всей вероятности unitialized переменная, как другие ответы предполагают.

12
ответ дан Franci Penov 24 November 2019 в 07:27
поделиться

Вещи высматривать:

переполнения Массива - отладчик Visual Studio вставляет дополнение, которое может остановить катастрофические отказы.

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

Соединение - является Вашим получением по запросу сборки конечных версий в корректных библиотеках.

Вещи попробовать:

Мини-дамп - действительно простой в использовании (просто ищут его в MSDN) даст Вам полный дамп катастрофического отказа для каждого потока. Вы просто загружаете вывод в Visual Studio, и это - как будто Вы отлаживали во время катастрофического отказа.

15
ответ дан morechilli 24 November 2019 в 07:27
поделиться

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

int* p;
....
if (p == 0) { // do stuff }

В режиме отладки код в, если не выполняется, но в режиме выпуска p содержит неопределенное значение, которое вряд ли будет 0, таким образом, код будет, часто выполняться вызывая катастрофический отказ.

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

49
ответ дан David Dibben 24 November 2019 в 07:27
поделиться

Vista SP1 имеет действительно хороший генератор аварийных дампов, встроенный в систему. К сожалению, по умолчанию он не включен!

См. Эту статью: http://msdn.microsoft.com/en-us/library/bb787181 (VS.85) .aspx

Преимущество этого подхода заключается в том, что в уязвимой системе не требуется устанавливать дополнительное программное обеспечение. Возьми его и разорви, детка!

1
ответ дан 24 November 2019 в 07:27
поделиться
Другие вопросы по тегам:

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