Форум программистов, компьютерный форум CyberForum.ru

Статический пул для класса с помошью class::operator new непонятное исключение? - C++

Восстановить пароль Регистрация
 
returnless
25 / 25 / 3
Регистрация: 05.08.2012
Сообщений: 83
15.08.2012, 10:00     Статический пул для класса с помошью class::operator new непонятное исключение? #1
Привет всем! Пытаюсь организовать статический пул(молниеносный аллокатор памяти.
) для некоторого класса. Написал сравнительный тест разница где то до 10 раз, статический пул быстрее.


Но есть одна проблема статический пул у меня по умолчанию имеет размер в 1кб класс весит 12 байт. В цикле они создаются и уничтожаются т.е. пул весь не занимается, однако при малом размере вылетает исключение. не пойму в чем дело, я же занимаю только первые 24 байта пула? Но если увеличеть размер пула void InitMemPool(unsigned int size = 1024*1024) все - ок. вылета нет.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
 
//Прототипы
void* getMemPool    ( unsigned int size ) ;
void freeMemPool(void* p );
 
void InitMemPool    ( unsigned int size ) ;
void TerminateMemPool();
 
enum {memFree, memUsed};
 
// Класс
class Box 
{
    float x;
    float y;
    float z;
public:
    Box(float _x = 0, float _y = 0, float _z = 0) 
    {
        x = _x;
        y = _y;
        z = _z;
    }
    float getVolume() { return x * y * z; }
    void show() { printf("box sizes: %f %f %f volume %f \n", x, y, z, getVolume());}
 
    void *operator new(size_t size) 
    { 
        return getMemPool(size);
    }
    void operator delete(void *p) 
    {
        freeMemPool(p);
    }
};
 
// Пул
unsigned gMemPoolSize = 0;
char*   gMemPool = NULL; // Пул - участок памяти
void*   gMemPoolPointers    [0xFF] = {0}; // Указатели с шагом в размер (Box) по пулу gMemPool
char        gMemPoolStatus  [0xFF] = {0}; // Статус указателей  1 - занят 0 - незанят
 
 
 
// Выделим пямять для пула
void InitMemPool(unsigned int size = 1024) 
{
    gMemPool = (char*) malloc(size);
    gMemPoolSize = size;
    // Расстановка указателей адрессации на участки памяти пула.
    for (int i = 0; i < 0xFF; i ++) 
    {
        gMemPoolPointers[i] = (void*)( (int)(gMemPool) + (int)( i * sizeof(Box)) );
    }
#ifndef NDEBUG
    printf("InitMemPool at %d size %d\n", (int) gMemPool, size);
    printf("Box Size %d\n", sizeof(Box));
    
    for (int i = 0; i < 0x0A; i ++) 
    {
        printf("Pool Index %d at %d size %d\n", i, (int) gMemPoolPointers[i], (int)(i < 1 ? (int)gMemPoolPointers[1] - (int)gMemPoolPointers[0] : (int)gMemPoolPointers[i] - (int)gMemPoolPointers[i-1])  );
    }
 
#endif
}
 
// Освободим память от пула
void TerminateMemPool() 
{
    
    free(gMemPool);
#ifndef NDEBUG
    printf("TerminateMemPool at %d size %d\n", (int) gMemPool, gMemPoolSize);
#endif
    gMemPool = NULL;
    gMemPoolSize = 0;
}
 
void* getMemPool(unsigned int size ) 
{
    
    for (int i = 0; i<0xFF; i++)
    {
        if (gMemPoolStatus[i] == memFree) 
        {
            gMemPoolStatus[i] = memUsed;
#ifndef NDEBUG
            printf("getMemPool size %d pool index %d at %d\n", size, i,  (int)gMemPoolPointers[i]);
#endif
            return gMemPoolPointers[i];
        } 
    }
}
 
void freeMemPool(void* p ) 
{
    int i = (int)( (int*)p - (int*)gMemPoolPointers[0] ); // вычисляем индекс указателя в пуле
    i = (int) (i / sizeof (Box));
 
    gMemPoolStatus[i] = memFree;
#ifndef NDEBUG
    printf("freeMemPool %u at %d\n", i, (int)p);
#endif
}
 
int main() 
{
    // test std new
    int time = GetTickCount()+1000;
    float v = 0.0f;
    unsigned iter = 0;
    while (time > GetTickCount() ) 
    {
        Box* a = ::new Box(1,1,1);
        Box* b = ::new Box(1,1,1);
 
        v += (a->getVolume() + b->getVolume());
        ::delete(a);
        ::delete(b);
 
        iter++;
    }
 
    printf("sum of volumes %f iterations %d \n", v, iter);
 
    // test static pool new
    time = GetTickCount()+1000;
    InitMemPool();
    v = 0.0f;
    iter =0;
    while (time > GetTickCount() ) 
    {
        Box* a = new Box(1,1,1);
        Box* b = new Box(1,1,1);
 
        v += (a->getVolume() + b->getVolume());
 
        delete(a);
        delete(b);
        iter++;
    }
 
    TerminateMemPool();
    printf("sum of volumes %f iterations %d \n", v, iter);
 
    system("pause");
    return 0;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.08.2012, 10:00     Статический пул для класса с помошью class::operator new непонятное исключение?
Посмотрите здесь:

C++ Статический константный объект класса
operator[][] для класса C++
[C++] перегрузка operator<< для шаблонного класса C++
C++ Статический и динамический экземпляры класса
C++ Что это bool operator== (const CLASS&) const;
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
John Prick
754 / 687 / 123
Регистрация: 27.07.2012
Сообщений: 1,974
Завершенные тесты: 3
15.08.2012, 11:41     Статический пул для класса с помошью class::operator new непонятное исключение? #2
Может быть, вся проблема в этих волшебных числах:

Цитата Сообщение от returnless Посмотреть сообщение
1024
0xFF
Ведь, судя по коду, при выделении памяти для одного элемента, просматривается 0xFF элементов, а если пул на столько не рассчитан - вот вам и исключение.
returnless
25 / 25 / 3
Регистрация: 05.08.2012
Сообщений: 83
15.08.2012, 14:14  [ТС]     Статический пул для класса с помошью class::operator new непонятное исключение? #3
1024 - размер пула (байты)
0xFF = 255 это максимальное кол-во классов которые может разместить аллокаотор в выделенном ему участке памяти. магическое 255 это мера временная. 85(1024/12) элементов не спасло ситуацию. поэтому тут нету проблемы поскольку 2 класса создаются (24 байта выделяются), совершается вызов методов и 2 класса - уничтожатся (24 байта помечаются свободными) потолок в 85 и тем более в 255 созданных класса не возможна.

Однако все равно спс, на 100ом+ шаге отладки 2-ого цикла я обнаружил несколько багов во время delete(a) глянул gMemPoolStatus по идее там должно быть только два взведенных флага gMemPoolStatus [0] и [1] = 1 (занято) а оказалось 40 элементов gMemPoolStatus [0-40] все = 1. Откуда столько взялось, опять непонятно (
returnless
25 / 25 / 3
Регистрация: 05.08.2012
Сообщений: 83
15.08.2012, 16:00  [ТС]     Статический пул для класса с помошью class::operator new непонятное исключение? #4
Решил проблему. баг был в коде удаления не правильно вычислялся индекс.
Исправил.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
void freeMemPool(void* p ) 
{
    [B]int i = (int)( (int)p - (int)gMemPoolPointers[0] );[/B] // вычисляем индекс указателя в пуле
    i = (int) (i / sizeof (Box));
 
    if (i <= POOL_POSITIONS) 
    { 
        gMemPoolStatus[i] = memFree;
#ifndef NDEBUG
    printf("freeMemPool %u at %d\n", i, (int)p);
#endif
    }
}
было
C++
1
[B]int i = (int)( (int*)p - (int*)gMemPoolPointers[0] );[/B]
результаты теста. 3 млн. итераций std::new и 41млн итераций static pool new.
Миниатюры
Статический пул для класса с помошью class::operator new непонятное исключение?  
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
15.08.2012, 16:21     Статический пул для класса с помошью class::operator new непонятное исключение? #5
Кстати, насчёт индексов. Зачем вы предвычисляете и храните указатели на объекты (gMemPoolPointers)? Можно ж сделать обратное преобразование, как у вас в freeMem(). Особенно в свете того, что объекты чаще всего выравниваются и умножать/делить на их размеры можно быстро.
returnless
25 / 25 / 3
Регистрация: 05.08.2012
Сообщений: 83
15.08.2012, 17:19  [ТС]     Статический пул для класса с помошью class::operator new непонятное исключение? #6
да я тоже было подумал об этом нафига мне массив указателей которые адресуют gMemPool с определенным шагом. щас заменил выделение на как ты говришь - обратное преобразование
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void* getMemPool(unsigned int size ) 
{
    
    for (int i = 0; i<POOL_POSITIONS; i++)
    {
        if (gMemPoolStatus[i] == memFree) 
        {
            gMemPoolStatus[i] = memUsed;
#ifndef NDEBUG
            printf("getMemPool size %d pool index %d at %d\n", size, i,  (int)gMemPoolPointers[i]);
#endif
            //return gMemPoolPointers[i];
            return (int*)((int)gMemPool + (i * sizeof(Box)) );
        } 
    }
    return NULL;
}
и получил падение скорости выделения памяти примерно на весь тест первого цикла.
то есть быстрее будет, если имеются предвычисленные указатели, а не производить калькуляции. ну в общем - mem VS calculations.
Миниатюры
Статический пул для класса с помошью class::operator new непонятное исключение?  
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.08.2012, 18:12     Статический пул для класса с помошью class::operator new непонятное исключение?
Еще ссылки по теме:

Пегерузка operator<< или свое универсальное исключение C++
operator+ как член класса C++
operator= для шаблона класса C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
15.08.2012, 18:12     Статический пул для класса с помошью class::operator new непонятное исключение? #7
Компилил
вот этот код
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
 
#define NDEBUG
 
//Прототипы
void* getMemPool    ( unsigned int size ) ;
void freeMemPool(void* p );
 
void InitMemPool    ( unsigned int size ) ;
void TerminateMemPool();
 
enum {memFree, memUsed};
 
// Класс
class Box 
{
    float x;
    float y;
    float z;
public:
    Box(float _x = 0, float _y = 0, float _z = 0) 
    {
        x = _x;
        y = _y;
        z = _z;
    }
    float getVolume() { return x * y * z; }
    void show() { printf("box sizes: %f %f %f volume %f \n", x, y, z, getVolume());}
 
    void *operator new(size_t size) 
    { 
        return getMemPool(size);
    }
    void operator delete(void *p) 
    {
        freeMemPool(p);
    }
};
 
// Пул
const size_t POOL_POSITIONS = 0xFF;
 
unsigned gMemPoolSize = 0;
char*   gMemPool = NULL; // Пул - участок памяти
void*   gMemPoolPointers    [POOL_POSITIONS] = {0}; // Указатели с шагом в размер (Box) по пулу gMemPool
char        gMemPoolStatus  [POOL_POSITIONS] = {0}; // Статус указателей  1 - занят 0 - незанят
 
 
 
// Выделим пямять для пула
void InitMemPool(unsigned int size = 1024) 
{
    gMemPool = (char*) malloc(size);
    gMemPoolSize = size;
#ifdef PRECALC
    // Расстановка указателей адрессации на участки памяти пула.
    for (int i = 0; i < POOL_POSITIONS; i ++) 
    {
        gMemPoolPointers[i] = gMemPool + i * sizeof(Box);
    }
#endif
#ifndef NDEBUG
    printf("InitMemPool at %d size %d\n", (int) gMemPool, size);
    printf("Box Size %d\n", sizeof(Box));
    
    for (int i = 0; i < 0x0A; i ++) 
    {
        printf("Pool Index %d at %d size %d\n", i, (int) gMemPoolPointers[i], (int)(i < 1 ? (int)gMemPoolPointers[1] - (int)gMemPoolPointers[0] : (int)gMemPoolPointers[i] - (int)gMemPoolPointers[i-1])  );
    }
 
#endif
}
 
// Освободим память от пула
void TerminateMemPool() 
{
    
    free(gMemPool);
#ifndef NDEBUG
    printf("TerminateMemPool at %d size %d\n", (int) gMemPool, gMemPoolSize);
#endif
    gMemPool = NULL;
    gMemPoolSize = 0;
}
 
 
void* getMemPool(unsigned int size ) 
{
    
    for (int i = 0; i<POOL_POSITIONS; i++)
    {
        if (gMemPoolStatus[i] == memFree) 
        {
            gMemPoolStatus[i] = memUsed;
#ifndef NDEBUG
            printf("getMemPool size %d pool index %d at %d\n", size, i,  (int)gMemPoolPointers[i]);
#endif
#ifdef PRECALC
            return gMemPoolPointers[i];
#else
            return gMemPool + i * sizeof(Box);
#endif
        } 
    }
}
 
void freeMemPool(void* p ) 
{
    int i = ((char*)p - gMemPool) / sizeof (Box); // вычисляем индекс указателя в пуле
 
    if (i <= POOL_POSITIONS) 
    { 
        gMemPoolStatus[i] = memFree;
#ifndef NDEBUG
    printf("freeMemPool %u at %d\n", i, (int)p);
#endif
    }
}
 
int main() 
{
    // test std new
    int time = GetTickCount()+1000;
    float v = 0.0f;
    unsigned iter = 0;
    while (time > GetTickCount() ) 
    {
        Box* a = ::new Box(1,1,1);
        Box* b = ::new Box(1,1,1);
 
        v += (a->getVolume() + b->getVolume());
        ::delete(a);
        ::delete(b);
 
        iter++;
    }
 
    printf("%d\t", iter);
 
    // test static pool new
    time = GetTickCount()+1000;
    InitMemPool();
    v = 0.0f;
    iter =0;
    while (time > GetTickCount() ) 
    {
        Box* a = new Box(1,1,1);
        Box* b = new Box(1,1,1);
 
        v += (a->getVolume() + b->getVolume());
 
        delete(a);
        delete(b);
        iter++;
    }
 
    TerminateMemPool();
    printf("%d\n", iter);
    return 0;
}

Получил такие результаты. Усреднено за десять прогонов (количество итераций за секунду, больше = лучше)
Код
                     Стандарт         Ручное
Вычисление на лету    980 474      9 220 637
Предвычисление        905 384     11 259 098
Итого предвычисление на 18% медленнее, зато экономит омгппц 81 мс времени и аж целый килобайт памяти на формировании индекса.

Ок, понял.
Yandex
Объявления
15.08.2012, 18:12     Статический пул для класса с помошью class::operator new непонятное исключение?
Ответ Создать тему
Опции темы

Текущее время: 22:28. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru