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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
returnless
26 / 26 / 3
Регистрация: 05.08.2012
Сообщений: 83
#1

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

15.08.2012, 10:00. Просмотров 507. Ответов 6
Метки нет (Все метки)

Привет всем! Пытаюсь организовать статический пул(молниеносный аллокатор памяти.
) для некоторого класса. Написал сравнительный тест разница где то до 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;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.08.2012, 10:00
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Статический пул для класса с помошью class::operator new непонятное исключение? (C++):

Class & operator's |Error: undefined reference to operator - C++
Компилирует нормально, но когда хочу использовать оператор выдает ошибку:undefined reference to 'operator..(Fraction const&amp;, Fraction...

Class и operator[] для N мерных массивов (требуется совет от опытных) - C++
Добрый день :senor: Верно ли, что для того, чтобы получить доступ к элементу в N мерном массиве(private) достаточно лишь перегрузить...

Operator< для класса - C++
Всем добра, что-то я туплю подскажите как определить operator&lt; для класса, в классе два значение если какое-нибудь меньше то тру. class...

operator[][] для класса - C++
Добрый день, создал класс где храниться массив, и хотелось бы иметь напрямю доступ через по типу class Matrix { .... int ** data; ...

Перегрузка operator<< для шаблонного класса - C++
Добрый день не могу понять как реализовать перегрузку &lt;&lt; для шаблонного класса template &lt;class T&gt; class List { public: ...

Перегрузка operator>> для производного класса - C++
Базовый класс: Taxi_Car.h: #pragma once #include&lt;string&gt; using namespace std; class Taxi_Car { string Marka;

6
John Prick
801 / 734 / 145
Регистрация: 27.07.2012
Сообщений: 2,107
Завершенные тесты: 3
15.08.2012, 11:41 #2
Может быть, вся проблема в этих волшебных числах:

Цитата Сообщение от returnless Посмотреть сообщение
1024
0xFF
Ведь, судя по коду, при выделении памяти для одного элемента, просматривается 0xFF элементов, а если пул на столько не рассчитан - вот вам и исключение.
1
returnless
26 / 26 / 3
Регистрация: 05.08.2012
Сообщений: 83
15.08.2012, 14:14  [ТС] #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. Откуда столько взялось, опять непонятно (
0
returnless
26 / 26 / 3
Регистрация: 05.08.2012
Сообщений: 83
15.08.2012, 16:00  [ТС] #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.
0
Миниатюры
Статический пул для класса с помошью class::operator new непонятное исключение?  
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
15.08.2012, 16:21 #5
Кстати, насчёт индексов. Зачем вы предвычисляете и храните указатели на объекты (gMemPoolPointers)? Можно ж сделать обратное преобразование, как у вас в freeMem(). Особенно в свете того, что объекты чаще всего выравниваются и умножать/делить на их размеры можно быстро.
1
returnless
26 / 26 / 3
Регистрация: 05.08.2012
Сообщений: 83
15.08.2012, 17:19  [ТС] #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.
0
Миниатюры
Статический пул для класса с помошью class::operator new непонятное исключение?  
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
15.08.2012, 18:12 #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 мс времени и аж целый килобайт памяти на формировании индекса.

Ок, понял.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.08.2012, 18:12
Привет! Вот еще темы с ответами:

Реализовать перегрузку operator+() для пользователского класса - C++
Есть класс ДРОБЬ, его члены ЧИСЛИТЕЛЬ И ЗНАМЕНАТЕЛЬ, а методы - конструктор и методы вывода. исходные данные - 4 обычные дроби. мне нужно...

Перегрузка operator< для двух экземпляров класса отрезок - C++
Всем добра, в классе отрезок хочу перегрузить операцию &lt; правильно ли я сделал ? При этом отрезок с координатами x1=1 y1=1 и x2=4 y2=4...

Перегрузить operator<<() для шаблонного класса (перегрузка оператора вывода) - C++
Здравствуйте. Перегружаю оператор вывода для шаблонного класса. using namespace std; template &lt;class Element&gt; class List { ...

Написать header file для производного класса class - C++
Vsem privet,kto mojet napisat zdes header file. Vse funkcii uje zapisal. Nujno zapisat nasledstvennost mejdu 5 klassami. Vot moi kod....


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

Или воспользуйтесь поиском по форуму:
7
Yandex
Объявления
15.08.2012, 18:12
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru