утечек памяти нет, а New выбрасывает Exception-ы после долгой работы. почему ?
В дебуг режиме -
#include <new>
typedef struct _CrtMemBlockHeader1
{
struct _CrtMemBlockHeader1 * pBlockHeaderNext;
struct _CrtMemBlockHeader1 * pBlockHeaderPrev;
char * szFileName;
int nLine;
size_t nDataSize;
int nBlockUse;
long lRequest;
unsigned char gap[4]; //nNoMansLandSize
/* followed by:
* unsigned char data[nDataSize];
* unsigned char anotherGap[nNoMansLandSize];
*/
} _CrtMemBlockHeader1;
void * operator new(size_t size);
void operator delete(void *p);
void * operator new[](size_t size);
void operator delete[](void *p);
int _tmain(int argc, _TCHAR* argv[])
{
int *k = new int;
char *str = new char[100];
*k = 10;
strcpy(str, "Hi pipl!!!");
delete k;
delete [] str;
return 0;
}
void * operator new(size_t size)
{
return malloc(size);
}
void * operator new[](size_t size)
{
return malloc(size);
}
void operator delete(void *p)
{
_CrtMemBlockHeader1 *pHead = (((_CrtMemBlockHeader1 *)p)-1);
size_t x = (((_CrtMemBlockHeader1 *)p)-1)->nDataSize;
free(p);
}
void operator delete[](void *p)
{
_CrtMemBlockHeader1 *pHead = (((_CrtMemBlockHeader1 *)p)-1);
size_t x = (((_CrtMemBlockHeader1 *)p)-1)->nDataSize;
free(p);
}
x - количество байтов освобождаемых.
2) Вопрос на засыпку:
Если вызвать delete от недействительного указателя, память испортится ???? - Испортится и память и прога, теоретически вплоть до форматирования винта.
1) А как я в delete узнаю, скока я байт освобождаю, если передаётся в него токо указатель?
Память выделяется и освобождается блоками (страницми, в Win32 по 64 К), если одновременно будет освобождается более одного блока, то освободится только последний.
Память выделяется и освобождается блоками (страницми, в Win32 по 64 К), если одновременно будет освобождается более одного блока, то освободится только последний.
Откуда такие сведения?
Откуда такие сведения?
Со школьной скамьи :)
Со школьной скамьи :)
Может номер школы назовешь, а заодно и ссылку приведешь на указание подобных проблем в многопоточной среде?
В дебуг режиме -
{
struct _CrtMemBlockHeader1 * pBlockHeaderNext;
struct _CrtMemBlockHeader1 * pBlockHeaderPrev;
char * szFileName;
int nLine;
size_t nDataSize;
int nBlockUse;
long lRequest;
unsigned char gap[4]; //nNoMansLandSize
} _CrtMemBlockHeader1;
void operator delete[](void *p)
{
_CrtMemBlockHeader1 *pHead = (((_CrtMemBlockHeader1 *)p)-1);
size_t x = (((_CrtMemBlockHeader1 *)p)-1)->nDataSize;
free(p);
}
x - количество байтов освобождаемых.
Вопрос: а по nBlockUse можно узнать, был ли уже освобождён данный блок, тоесть можно ли для него вызвать free.
фрагментация памяти :
допустим допустимый размер кучи - 100 байт. И эти 100 байт распределены следующим образом:
00 - 29 Свободно ( 30 байт )
30 - 79 Занято ( 50 байт )
80 - 99 Свободно ( 20 байт )
Таким образом имеем ситуацию : утечек памяти нет, свободной памяти - 50 байт, но выделить программа может только 20 или 30 байт. Поэтому если запрашиваем 40 байт нас посылают....
Я доступно излагаю ? (c)
Вопрос на засыпку:
Если вызвать delete от недействительного указателя, память испортится ???? - Испортится и память и прога, теоретически вплоть до форматирования винта.
По идее, при попытке освободить неверный блок должен вылететь эксэпшн. Но вылететь он может и не сразу, а при выходе из программы (когда MFC проводит дамп выделенной/освобождённой памяти). Для проверки целостности Heap'а можно использовать HeapValidate()
... еще вероятнее, он удаляет объект, который потом опять юзается через указатель.
Скорее всего так оно и есть, тк программа перестает вываливаться когда diesel_den выкидывает delete.
Но наши гадания будут продолжаться еще долго, если автор с упорством, достйным лучшего применения, будет и дальше сам искать ошибку в new() и весь форум направлять в это русло
Короче фигня это все, я не верю что дизель забивает всю доступную память. И вероятность фрагментации тоже очень низкая. Скорее всего юзается невыделеный указатель, или, еще вероятнее, он удаляет объект, который потом опять юзается через указатель.
Так как программа работает сутками и при этом интенсивно использует выделение\освобождение памяти небольшими кусками то вероятность фрагментации не такая уж и низкая. У меня и не такое бывало. И потом что ему стоит проверить перед вызом new в котором кидается exception проверить максимальный размер блока и таким образом подтвердить или отвергнуть мое предположение.
Так как программа работает сутками и при этом интенсивно использует выделение\освобождение памяти небольшими кусками то вероятность фрагментации не такая уж и низкая. У меня и не такое бывало. И потом что ему стоит проверить перед вызом new в котором кидается exception проверить максимальный размер блока и таким образом подтвердить или отвергнуть мое предположение.
Лучше всего выделить всю необходимую память при загрузке программы и освободить при закрытии.
Вызывай _heapmin каждый раз, когда программа выделяет блоки размера, привышающего предел возможного для кучи малых блоков (по умолчанию 480 байт), так как блоками меньшего размера управляет сама CRT.
Также может возникнуть проблема при вызове HeapFree, если передать ей указатель на малый блок, полученный от new, т.к. new при выделении пямяти не использовал память кучи и не вызывал HeapAlloc.
Я доступно излагаю ? (c)
доступно, я вас понял. вот только Alexandoros правильно говорит - фрагментация памяти, либо её нехватка в данном случае не может являться причиной глюков.
А выложить исходники я очень боюсь - это собственность фирмы, в которой я работаю :(
Также может возникнуть проблема при вызове HeapFree, если передать ей указатель на малый блок, полученный от new, т.к. new при выделении пямяти не использовал память кучи и не вызывал HeapAlloc.
new юзает HeapAlloc.
diesel_den если ты на 100% уверен, что глюк идет именно от нью, а не от юзанья невалидного блока - то зделай еще проще.Перед всеми нью поставь инкремент счетчика, а после делета - декремент, тогда точно будеш знать сколько байт выделено в даный момент.
Но повторю - твоя прога вылетает из-за того, что один поток юзает указатель, который уже грохнул другой поток.
new юзает HeapAlloc.
diesel_den если ты на 100% уверен, что глюк идет именно от нью, а не от юзанья невалидного блока - то зделай еще проще.Перед всеми нью поставь инкремент счетчика, а после делета - декремент, тогда точно будеш знать сколько байт выделено в даный момент.
Но повторю - твоя прога вылетает из-за того, что один поток юзает указатель, который уже грохнул другой поток.
disel_den Заключи всю свою прогр. в try - catch( ... ) затем распечатай что покажут в саtch GetLastError() GetExceptionCode() и сразу увидишь оператор на кот. программа вываливается
доступно, я вас понял. вот только Alexandoros правильно говорит - фрагментация памяти, либо её нехватка в данном случае не может являться причиной глюков.
А выложить исходники я очень боюсь - это собственность фирмы, в которой я работаю :(
Да я не прошу тебя выкладывать здесь исходники. Просто перед первым new который кидает exception поставь функцию HeapCommit ( назначение которой посмотри в MSDN ) и проверь максимально доступный размер куска памяти и таким образом явно подтверди или опровергни мое предположение. Впрочем делать нефиг, счас пороюсь в исходниках посмотрю в каких случаях может в принципе выбрасывасться исключение.
// compile with: /EHsc
#include<new>
#include<iostream>
using namespace std;
int main( )
{
char* ptr;
try
{
ptr = new char[~size_t(0)/2];
delete[ ] ptr;
}
catch( bad_alloc &ba)
{
cout << ba.what( ) << endl;
};
}
вот нашел в MSDN попробуй аналогично задействовать метод what класса bad_alloc что бы узнать причину exception.
Но повторю - твоя прога вылетает из-за того, что один поток юзает указатель, который уже грохнул другой поток.
Абсолютно с вами согласен, вот только не могу найти эту ошибку
Абсолютно с вами согласен, вот только не могу найти эту ошибку
В 3-й раз
Заключи всю свою прогр. в try - catch( ... ) затем распечатай что покажут в саtch GetLastError() GetExceptionCode() и сразу увидишь оператор на кот. программа вываливается
В 3-й раз
Заключи всю свою прогр. в try - catch( ... ) затем распечатай что покажут в саtch GetLastError() GetExceptionCode() и сразу увидишь оператор на кот. программа вываливается
А я в очередной раз повторяю, что у меня все операции уже давно заключены в try/catch, прога вываливается каждый раз в произвольном месте. Единственное, что обьеденяет эти сбои - их причина - нарушение кучи.
А я в очередной раз повторяю, что у меня все операции уже давно заключены в try/catch, прога вываливается каждый раз в произвольном месте. Единственное, что обьеденяет эти сбои - их причина - нарушение кучи.
Не поленюсь и в 4-й(уже почти интересно)
нужно закинуть в try/catch ВСЮ программу а не отдельные new и delete. И кажд поток должен быть заключен в свой try/catch. Только не говори что catch( ... ) не выловит Exception.
А с кучей и тебя все в порядке
dynamic_cast<CClass2 *>(Ferma.GetObj(13))->DoSomething();
...
Ferma.DeleteObj(34); // здесь проверяй удален уже объект или нет. Если указатель в нуле - значит удален.
...
int index = Ferma.CreateObj(ObjType);
Панятна??? Работай, и не пость воды сюда больше :D
А я в очередной раз повторяю, что у меня все операции уже давно заключены в try/catch, прога вываливается каждый раз в произвольном месте. Единственное, что обьеденяет эти сбои - их причина - нарушение кучи.
Элементарный пример: компилируем
char * p = new char[12];
delete[] (char *)(p+2);
2.
char * p = new char[12];
delete[] p;
delete[] p;
Смотрим результат и делаем выводы. Фрагментация тут тоже не причём, если эксепшн говорит об Access Violation. Да элементарно ты считай количество выделенных/удалённых объектов + выделенной/освобождённой памяти. Если всё ровно, значит жук - использование уже удалённого указателя. Обнуляй ты все указатели после удаления, ёпрст!!! Уже неделю все только и делают, что обсуждают твой new, а ты всё ошибку найти не можешь... Да с таким количеством разных советов можно было уже свой оператор написать: тут и делать уже не надо ничего - копируй посты да вставляй в прогу :) Сделай уже ты нормально эти злементарные вещи и перестань наконец людей мучать
как правильно удалить?
delete[] p;
или
delete[] (char*)p;
То, что delete p; - не годиться, это я понимаю.
int* p = (int*)new char[4];
как правильно удалить?
delete[] p;
или
delete[] (char*)p;
То, что delete p; - не годиться, это я понимаю.
мда... похоже на весеннее обострение.... на почве нехватки витаминов..... ты пробовал поговорить об этом со своим психиатром ?
мда... похоже на весеннее обострение.... на почве нехватки витаминов..... ты пробовал поговорить об этом со своим психиатром ?
А слабо не выпендриваться и ответить по-существу?
Или Вы давно о таких тонких нюансах не думали?
int* p = (int*)new char[4];
как правильно удалить?
delete[] p;
или
delete[] (char*)p;
То, что delete p; - не годиться, это я понимаю.
А зачем тебе так надо написать? Неужели нельзя по-другому?
ну, а если так, то delete[] p;
А зачем тебе так надо написать? Неужели нельзя по-другому?
ну, а если так, то delete[] p;
Конечно я не собираюсь так писать. Но в моей проге есть похожий код. Есть структура, последнее поле которой должно иметь переменную длину. Вот и выделяю я под экземпляр этой структуры память операцией new char[нужная длина], привожу полученный указатель к типу "указатель на мою структуру" и далее через этот указатель работаю с экземпляром этой структуры.
Конечно я не собираюсь так писать. Но в моей проге есть похожий код. Есть структура, последнее поле которой должно иметь переменную длину. Вот и выделяю я под экземпляр этой структуры память операцией new char[нужная длина], привожу полученный указатель к типу "указатель на мою структуру" и далее через этот указатель работаю с экземпляром этой структуры.
{
...
char *str;
};
MyStruct.str = new char[80];
...
delete[] MyStruct.str;
Я правильно тебя понял?
{
...
char *str;
};
MyStruct.str = new char[80];
...
delete[] MyStruct.str;
Я правильно тебя понял?
нет
нет
Видимо, такая конструкция:
{
......
type arr[1];
};
A* pA = (A*)new char[sizeof(A) + (n-1)*sizeof(type)];
Только вот это не очень хороший стиль программирования.
Единственное применение, которое я могу представить, это передача некоторому железу (в т.ч. в сеть), но и это можно решить иначе.
Видимо, такая конструкция:
{
......
type arr[1];
};
A* pA = (A*)new char[sizeof(A) + (n-1)*sizeof(type)];
Только вот это не очень хороший стиль программирования.
Единственное применение, которое я могу представить, это передача некоторому железу (в т.ч. в сеть), но и это можно решить иначе.
Зачем гадать, может он сам предоставит пример?
Зачем гадать, может он сам предоставит пример?
Ну в общем Green написал всё верно. И применение он написал близкое к моему, так как в своей системе я пытаюсь наладить обмен "пакетами" переменной длины, как бы свой протокол.
Ну в общем Green написал всё верно. И применение он написал близкое к моему, так как в своей системе я пытаюсь наладить обмен "пакетами" переменной длины, как бы свой протокол.
А почему не используешь вариант, описанный AndreySar? Если уж юзаешь new/delete, почему бы деструктор не написать для структуры, и тогда не возникало бы никакой неопределённости, связанной с правильностью удаления
А почему не используешь вариант, описанный AndreySar? Если уж юзаешь new/delete, почему бы деструктор не написать для структуры, и тогда не возникало бы никакой неопределённости, связанной с правильностью удаления
прикол в том, что байт может прийти меньше, чем сумма размеров статических полей структуры. в моём случае некоторым модулям системы не нужны последние поля (причём у разных модулей кол-во нужных от начала полей разное). и я не хочу делить операцию пересылки пакета на две части (пересылка постоянной составляющей и пересылка составляющей переменной длины), так как это просто неудобно, а я стараюсь написать "эллегантный" код.
а я стараюсь написать "эллегантный" код.
Использование переменной длины - это совсем не "элегантный код". Лучше сделай классы без всяких переменных длин, с обычными агрегациями и методами сериализации.