Можно ли пометить сегмент памяти как «вне границ», поэтому менеджер кучи не выделяет от него?

StackOverflow https://stackoverflow.com/questions/4274058

Вопрос

Раньше сегодня я спросил этот вопрос.

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

Испытание загрузки от отладчика

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05560194     /* Different memory location */

Испытание загрузки от командной строки

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05176960     /* Same memory location */

В итоге:

  • При запуске теста устройства из командная строка, последующие звонки на new распределить ан Object (deleteпредыдущий Object Перед выделением нового) всегда верните такой же адрес в памяти.
  • При запуске теста устройства из отладчик, последующие звонки на new распределить ан Object (deleteпредыдущий Object до выделения нового) всегда верните уникальный адрес в памяти.

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

Есть 2 части к моему вопросу:

  1. Почему Manager Re-Manager повторно использует одну и ту же часть памяти при запуске модульного теста из командной строки, но не при запуске теста устройства от отладчика?

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


1Очевидно, что один из способов сделать это, это не удалить исходный объект, но часть кода, который выделяет это в моем производственном коде, и я делаю это, приведет к утечкам памяти.

Это было полезно?

Решение

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

Что вы делаете, это:

Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed

Вы должны вместо того, чтобы реструктурировать тест на единицу, чтобы он работает так:

Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it.  If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests

Другие советы

Вы могли бы заменить new а также delete С вашими собственными версиями, которые имеют поведение, которое вы хотите.

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

Ты мог бы написать пользовательский менеджер так как Пользователь Андреас Брин предлагает, но что бы это сделать? Это не редуктовать память из воздуха, она просит его где-то, как CRT Heap или куча операционной системы.

Сценарий A. Это не вернет память в базовую кучу - у вас будет утечка, а блок памяти все еще будет отображаться в адресное пространство, и оно будет доступно.

Сценарий B. Это вернет память в базовую кучу - тогда, когда ваш Manager пытается выделить память снова, в основном куча может снова вернуть этот блок. Также вы не знаете, что делает базовая куча, когда вы возвращаете память к нему. Это может сделать это незначительным или нет - поэтому доступ к этой памяти может сбиться или нет.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top