Из управления памятью, повреждения "кучи" и C++

Короткие и простые: поскольку элементы, которые вы ищете, не существуют в документе (пока).


В оставшуюся часть этого ответа я буду использовать getElementById как пример, но то же самое относится к getElementsByTagName , querySelector и любому другому методу DOM, который выбирает элементы.

Возможные причины

Есть две причины, по которым элемент может не существовать:

  1. Элемент с переданным идентификатором действительно не существует в документе. Вы должны дважды проверить, что идентификатор, который вы передаете на getElementById, действительно соответствует идентификатору существующего элемента в (сгенерированном) HTML и что у вас не было с ошибкой идентификатор (идентификаторы чувствительный !). Кстати, в большинстве современных браузеров , которые реализуют методы querySelector() и querySelectorAll(), нотация стиля CSS используется для извлечения элемента его id, например: document.querySelector('#elementID'), в отличие от способа, с помощью которого элемент извлекается его id в [[16]; в первом символе # необходимо, во втором это приведет к тому, что элемент не будет извлечен.
  2. Элемент не существует в данный момент , который вы вызываете getElementById ].

Последний случай довольно распространен. Браузеры анализируют и обрабатывают HTML сверху вниз. Это означает, что любой вызов элемента DOM, который встречается до появления этого элемента DOM в HTML, не будет выполнен.

Рассмотрим следующий пример:



Появляется div после script. В настоящий момент сценарий выполняется, элемент не существует , но и getElementById вернут null.

jQuery

То же самое относится к все селекторы с jQuery. jQuery не найдет элементов, если вы ошибочно написали ваш селектор, или вы пытаетесь выбрать их , прежде чем они на самом деле существуют .

Добавленный поворот - это когда jQuery не найден потому, что вы загрузили скрипт без протокола и запускаетесь из файловой системы:


этот синтаксис используется, чтобы позволить сценарию загружаться через HTTPS на странице с протоколом https: // и для загрузки HTTP-версии на странице с протоколом http: //

У этого есть неудачный побочный эффект попытки и невозможность загрузить file://somecdn.somewhere.com...


Решения

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

Это может быть обеспечено просто добавив ваш JavaScript после к соответствующему элементу DOM

, и в этом случае вы также можете поместить код непосредственно перед тегом закрывающего тела () (все DOM элементы будут доступны в момент выполнения скрипта). [/ g3 6]

Другие решения включают прослушивание событий load [MDN] или DOMContentLoaded [MDN] . В этих случаях не имеет значения, где в документе вы помещаете код JavaScript, вам просто нужно запомнить, чтобы весь обработчик DOM обрабатывался в обработчиках событий.

Пример:

window.onload = function() {
    // process DOM elements here
};

// or

// does not work IE 8 and below
document.addEventListener('DOMContentLoaded', function() {
    // process DOM elements here
});

Более подробную информацию об обработке событий и различиях браузера см. в статьях на странице quirksmode.org .

jQuery

Сначала убедитесь, что jQuery загружен правильно , Используйте инструменты разработчика браузера , чтобы узнать, был ли найден файл jQuery и исправлен ли URL-адрес, если он не был (например, добавьте схему http: или https: в начале, отрегулируйте путь, и т. д.)

Прослушивание событий load / DOMContentLoaded - это именно то, что делает jQuery с .ready() [docs] . Весь ваш код jQuery, который влияет на элемент DOM, должен находиться внутри этого обработчика событий.

На самом деле в учебнике j8uery явно указано:

Как почти все, что мы делаем при использовании jQuery, читает или манипулирует объектной моделью документа (DOM), мы должны убедиться, что мы начинаем добавлять события и т. д., как только DOM готов.

Для этого мы регистрируем готовое событие для документа.

$(document).ready(function() {
   // do stuff when DOM is ready
});
blockquote>

В качестве альтернативы вы также можете использовать сокращенный синтаксис:

$(function() {
    // do stuff when DOM is ready
});

Оба эквивалентны.

18
задан sameera lakshitha 21 August 2017 в 19:53
поделиться

12 ответов

Это относительно дешевые механизмы для того, чтобы возможно решить проблему:

  1. Следят за моим вопрос о повреждении "кучи" - я обновляю с ответами, как они вытряхивают. Первое балансировалось new[] и delete[], но Вы уже делаете это.
  2. Дают valgrind больше движения; это - превосходный инструмент, и мне только жаль, что это не было доступно в соответствии с Windows. Я только замедляю Вашу программу приблизительно половиной, которая довольно хороша по сравнению с эквивалентами Windows.
  3. Думают об использовании Google Performance Tools как замена malloc/new.
  4. Вы вычистили все свои объектные файлы и запустились? Возможно, Ваш make-файл... "субоптимальный"
  5. , Вы не assert() луг достаточно в Вашем коде. Как я знаю это не видя его? Как то, чтобы чистить зубной нитью, никто assert() с достаточно в их коде. Добавьте в функции проверки для Ваших объектов и вызова, которые на методе запускаются и конец метода.
  6. Вы компиляция - стена ? В противном случае сделайте так.
  7. Находят себя инструментом линта как Линт ПК . Небольшое приложение как Ваше могло бы вписаться демонстрация линта ПК страница, не означая покупки для Вас!
  8. Проверка Вы АННУЛИРУЕТЕ указатели после deleteing их. Никому не нравится висячий указатель. Тот же концерт с заявленными но освобожденными указателями.
  9. Остановка с помощью массивов. Используйте вектор вместо этого.
  10. не используют необработанные указатели. Используйте интеллектуальный указатель . Не используйте auto_ptr! Та вещь... удивительна; его семантика очень нечетна. Вместо этого выберите один из интеллектуальные указатели Повышения , или что-то из [1 114] библиотека Loki .
22
ответ дан 30 November 2019 в 06:29
поделиться

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

В конечном счете мы отследили его вниз использование контрольных точек отладчика. Я попытаюсь описать процедуру здесь:

1) Находят причину отказа. Это смотрит от Вашего примера кода, что память для "exampleString" повреждается и так не может быть записана в. Давайте продолжим это предположение.

2) Набор точка останова в последнем известном местоположении, что "exampleString" используется или изменяется без любой проблемы.

3) Добавляют контрольную точку к элементу данных 'exampleString'. С моей версией g ++, строка хранится в _M_dataplus._M_p. Мы хотим знать, когда этот элемент данных изменяется. Техника GDB для этого:

(gdb) p &exampleString._M_dataplus._M_p
$3 = (char **) 0xbfccc2d8
(gdb)  watch *$3
Hardware watchpoint 1: *$3

я, очевидно, использую Linux с g ++ и gdb здесь, но я полагаю, что контрольные точки памяти доступны с большинством отладчиков.

4) Продолжаются, пока контрольная точка не инициирована:

Continuing.
Hardware watchpoint 2: *$3

Old value = 0xb7ec2604 ""
New value = 0x804a014 ""
0xb7e70a1c in std::string::_M_mutate () from /usr/lib/libstdc++.so.6
(gdb) where

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

причиной нашей ошибки был доступ к массиву с отрицательным индексом. Индекс был результатом броска указателя на 'интервал' modulos размер массива. Ошибка была пропущена valgrind и др. как адреса памяти, выделенные, когда выполнение под теми инструментами никогда не было" > MAX_INT" и поэтому никогда не приводило к отрицательному индексу.

10
ответ дан 30 November 2019 в 06:29
поделиться

Это могло быть повреждение "кучи", но это столь же вероятно быть повреждением стека. Право Jim. Нам действительно нужно немного больше контекста. Те две строки источника не говорят нам очень в изоляции. Могло быть любое количество вещей, вызывающих это (который является реальной радостью C/C++).

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

1
ответ дан 30 November 2019 в 06:29
поделиться

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

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

  1. Становятся удобными в отладчике.
  2. Начинают затаптывать вокруг в отладчике, чтобы видеть, можно ли найти что-нибудь, что выглядит подозрительным. Проверьте особенно для наблюдения то, что происходит во время exampleString = hello; строка.
  3. Проверка для проверки это на самом деле отказывает на exampleString = hello; строка, и не при выходе из некоторого блока включения (который мог заставить деструкторы стрелять).
  4. Проверка любое волшебство указателя Вы могли бы делать. Адресная арифметика с указателями, кастинг, и т.д.
  5. Проверка все Ваши выделения и освобождение для проверки они подобраны (никакое двойное освобождение).
  6. Удостоверяются, что Вы не возвращаете ссылок или указателей на объекты на стеке.

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

7
ответ дан 30 November 2019 в 06:29
поделиться

Некоторые места для запуска:

, Если Вы находитесь на окнах, и использующий Visual C++ 6 (я надеюсь богу, никто все еще не использует его в эти дни) это - реализация станд.:: строка не ориентирована на многопотоковое исполнение, и может привести к такого рода вещи.

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

На моем предыдущем рабочем месте мы использовали Compuware Boundschecker для помощи с этим. Это является коммерческим и очень дорогим, так может не быть опция.

Вот несколько свободных библиотек, которые могут быть несколько полезны

http://www.codeguru.com/cpp/misc/misc/memory/article.php/c3745/

http://www.codeproject.com/KB/cpp/MemLeakDetect.aspx

Hope, которая помогает. Повреждение памяти является местом sucky, чтобы быть в!

3
ответ дан 30 November 2019 в 06:29
поделиться

Код был просто примером того, где моя программа перестала работать (это было выделено на стеке, Jim). Я на самом деле не ищу, 'что я сделал неправильно', а скорее, 'как я диагностирую то, что я сделал неправильно'. Учите человека ловить рыбу и все это. Хотя смотря на вопрос, я не ясно дал понять достаточно. Слава Богу для функции редактирования.: ')

кроме того, я на самом деле зафиксировал станд.:: строковая проблема. Как? Путем замены его вектором, компиляцией, затем заменяя строку снова. Это было последовательно катастрофический отказ там и зафиксированный даже при том, что это... не могло. Там существует что-то противное, и я не уверен что. Я действительно хотел проверить одно время, я вручную выделяю память на "куче", хотя:

 this->map = new Area*[largestY + 1];
 for (int i = 0; i < largestY + 1; i++) {
     this->map[i] = new Area[largestX + 1];
 }

и удаление его:

for (int i = 0; i < largestY + 1; i++) {
    delete [] this->map[i];
}
delete [] this->map;

я не выделил 2-й массив с C++ прежде. Это, кажется, работает.

1
ответ дан 30 November 2019 в 06:29
поделиться

кроме того, я на самом деле зафиксировал станд.:: строковая проблема. Как? Путем замены его вектором, компиляцией, затем заменяя строку снова. Это последовательно отказывало там, и зафиксированный даже при том, что это... не могло. Там существует что-то противное, и я не уверен что.

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

1
ответ дан 30 November 2019 в 06:29
поделиться

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

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

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

1
ответ дан 30 November 2019 в 06:29
поделиться

Выполненный Очищают.

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

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

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

Они думали, что мы отлаживали богов, но затем мы впускаем их на секрете, таким образом, они могли работать, Очищают, прежде чем мы должны были использовать их код. :-)

http://www-306.ibm.com/software/awdtools/purify/unix/

(Это довольно дорого, но у них есть бесплатная загрузка оценки)

1
ответ дан 30 November 2019 в 06:29
поделиться

Насколько я могу сказать, что Ваш код является правильным. Принятие exampleString является станд.:: строка, которая имеет объем класса как Вы, описывает, необходимо смочь инициализировать/присвоить его тот путь. Возможно, существует некоторая другая проблема? Возможно, отрывок фактического кода помог бы поместить его в контекст.

Вопрос: действительно ли exampleString является указателем на строковый объект, созданный с новым?

0
ответ дан 30 November 2019 в 06:29
поделиться

Ваш код, как я вижу, не имеет никаких ошибок. Как был сказан, больше контекста необходимо.

, Если Вы уже не попробовали, установите gdb (gcc отладчик) и скомпилируйте программу с-g. Это скомпилирует в отладочной информации, которую может использовать gdb. После того как у Вас есть установленный gdb, выполняет его с программой (gdb). Это является полезным cheatsheat для использования gdb.

Набор точка останова для функции, которая производит ошибку и видит, каково значение exampleString. Также сделайте то же для любого параметра, Вы являетесь передающими к exampleString. Это должно, по крайней мере, сказать Вам если станд.:: строки допустимы.

я нашел, что ответ от эта статья был хорошим руководством об указателях.

1
ответ дан 30 November 2019 в 06:29
поделиться

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

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

, Если это помогает кому-либо, это - что-то, что Вы поправляетесь в том, как Вы приобретаете опыт.

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

1
ответ дан 30 November 2019 в 06:29
поделиться
Другие вопросы по тегам:

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