간단한 메모리풀 구현 (C++)
Moderator: 류광
-
- Posts: 290
- Joined: 2006-07-10 02:25
간단한 메모리풀 구현 (C++)
http://blog.naver.com/itioma/40032155038
C++ 로 구현할 수 있는 제일 덩치 작은 메모리 풀입니다.
헤더파일 하나, 소스파일 하나 받아가시면 되고요
(추가 - 현재 마지막 버전 : http://blog.naver.com/itioma/40040531964 )
사용법은
class A {...}; 이놈을
class A : public MemoryPooled {...}; 이렇게 바꾸기만 하면
new A 가 호출될 때마다 메모리 풀에서 적절한 메모리를 제공해줍니다.
delete A 가 호출되면 메모리를 회수해가고요.
풀 자체는 프로그램이 종료될 때 자동으로 사라집니다.
즉, 사용법이라곤 풀링을 원하는 클래스가 MemoryPooled 를 상속받도록 하는게 전부입니다.
주의점에 있듯이, new A[] 에 대해서는 관리해주지 않습니다.
왜냐면 제가 배열할당을 안쓰고 따로 만든 컨테이너를 쓰기 때문에... 그 기능은 안만들었죠 뭐. - _-
그리고 멀티쓰레드 지원 안합니다.
이것도 역시 제가 멀티쓰레드를 안쓰기 때문에... - _-
소스 길이를 보시면 알겠지만
그냥 '안쓰는 것보단 낫다' 정도만 만들어놨습니다.
(그래도 혼자 3시간이나 삽질하면서 만든거 ㅠ.ㅠ)
아 물론 메모리 단편화는 막아줍니다. 그것도 안된다면 메모리 풀이 아니죠.
한마디로 '메모리 풀 하나 쓰려고 다른 라이브러리를 통째로 끌어오긴 싫다'는 분들을 위한거.
메모리 체인은 EC++ Item 10 에 나와있는 방법을 사용했습니다.
EC++ 에 나온 방법은 클래스마다 풀을 달아줘야 한다는 단점이 있어서
너도나도 쓸 수 있는 공용 풀로 구현했습니다.
소스 공개되어있으니 분석해보시고
잘못된 부분 있으면 알려주시면 감사하겠습니다.
C++ 로 구현할 수 있는 제일 덩치 작은 메모리 풀입니다.
헤더파일 하나, 소스파일 하나 받아가시면 되고요
(추가 - 현재 마지막 버전 : http://blog.naver.com/itioma/40040531964 )
사용법은
class A {...}; 이놈을
class A : public MemoryPooled {...}; 이렇게 바꾸기만 하면
new A 가 호출될 때마다 메모리 풀에서 적절한 메모리를 제공해줍니다.
delete A 가 호출되면 메모리를 회수해가고요.
풀 자체는 프로그램이 종료될 때 자동으로 사라집니다.
즉, 사용법이라곤 풀링을 원하는 클래스가 MemoryPooled 를 상속받도록 하는게 전부입니다.
주의점에 있듯이, new A[] 에 대해서는 관리해주지 않습니다.
왜냐면 제가 배열할당을 안쓰고 따로 만든 컨테이너를 쓰기 때문에... 그 기능은 안만들었죠 뭐. - _-
그리고 멀티쓰레드 지원 안합니다.
이것도 역시 제가 멀티쓰레드를 안쓰기 때문에... - _-
소스 길이를 보시면 알겠지만
그냥 '안쓰는 것보단 낫다' 정도만 만들어놨습니다.
(그래도 혼자 3시간이나 삽질하면서 만든거 ㅠ.ㅠ)
아 물론 메모리 단편화는 막아줍니다. 그것도 안된다면 메모리 풀이 아니죠.
한마디로 '메모리 풀 하나 쓰려고 다른 라이브러리를 통째로 끌어오긴 싫다'는 분들을 위한거.
메모리 체인은 EC++ Item 10 에 나와있는 방법을 사용했습니다.
EC++ 에 나온 방법은 클래스마다 풀을 달아줘야 한다는 단점이 있어서
너도나도 쓸 수 있는 공용 풀로 구현했습니다.
소스 공개되어있으니 분석해보시고
잘못된 부분 있으면 알려주시면 감사하겠습니다.
Last edited by Remisa on 2008-06-04 11:33, edited 2 times in total.
-
- Posts: 1314
- Joined: 2003-03-04 10:21
- Contact:
공용으로 사용하는 풀이 있으면 편하기는 하지만
실제로는 클래스별로 풀이 있는 것이 지역성(한 시점에 사용하는 메모리는 근처인 경우가 많다.)면에서 더 좋습니다.
#1
#2
#1 과 #2 프로그램을 처음 실행할때는 성능은 거의 비슷합니다.
하지만 오래동안 실행되서 다른 코드에서 new, delete 가 많이 사용한 이후에
#2 의 objects[0] 과 objects[1] 거리는 언제나 sizeof(Object) 만큼이지만
#1 의 *objects[0] 과 *objects[1] 거리는 sizeof(Object) 보다 대개 늘어나게 됩니다.
이 거리가 운영체제가 관리하는 페이지 크기보다 커지면 실행 속도에 상당한 악영향을 미치게 됩니다.
----------------------------------
여기까지가 이론 설명이고...
코드 리뷰를 하면
의도는 블럭 단위로 메모리를 할당하시려고 한 것 같은데
전혀 다르게 코딩 되신 것 같습니다.
구조체 512 정도를 할당하니 60000 이상이 할당되더라구요
메모리 관리 프로그램을 만들때는 최대 할당 크기를 별도로 계산해서 평가하는 테스트 루틴을
넣어두시는 것이 좋습니다.
이 부분은 의도를 이해하기가 좀 힘듭니다.
메모리를 밀어주는 것 같은데, 방법을 다소 바꾸시면 불필요할듯해 보입니다.
memcpy(newBlock+i*cellSize, &nextAddress, ANC_SIZE); 에서 ANC_SIZE 의 경우 sizeof(void*) 인데,
위처럼 하셔도 괜찮습니다.
newBlock + i*cell 보다는 블럭 구조체를 하나 만드셔서 포인터 연산하시는게 더 보기 좋습니다.
이부분은 버그는 없지만 nextFreeCellMap[size] 에서 오버플로우가 한번 된다는 점이 좀 불안하죠 : )
실제로는 클래스별로 풀이 있는 것이 지역성(한 시점에 사용하는 메모리는 근처인 경우가 많다.)면에서 더 좋습니다.
#1
Code: Select all
vector<Object*> objects;
for (int i = 0; i != OBJ_NUM; ++i)
objects.push_back(new Object);
UseObjects(objects);
Code: Select all
Object objects[OBJ_NUM];
UseObjects(objects);
하지만 오래동안 실행되서 다른 코드에서 new, delete 가 많이 사용한 이후에
#2 의 objects[0] 과 objects[1] 거리는 언제나 sizeof(Object) 만큼이지만
#1 의 *objects[0] 과 *objects[1] 거리는 sizeof(Object) 보다 대개 늘어나게 됩니다.
이 거리가 운영체제가 관리하는 페이지 크기보다 커지면 실행 속도에 상당한 악영향을 미치게 됩니다.
----------------------------------
여기까지가 이론 설명이고...
코드 리뷰를 하면
Code: Select all
int cellSize = ANC_SIZE+objSize;
byte* newBlock = (byte*)malloc(MP_OBJ_PER_BLOCK * cellSize);
전혀 다르게 코딩 되신 것 같습니다.
구조체 512 정도를 할당하니 60000 이상이 할당되더라구요
메모리 관리 프로그램을 만들때는 최대 할당 크기를 별도로 계산해서 평가하는 테스트 루틴을
넣어두시는 것이 좋습니다.
Code: Select all
for (int i=1; i<MP_OBJ_PER_BLOCK-1; ++i)
{ // Form a linked list with memory cells
nextAddress = newBlock + (i+1)*cellSize;
memcpy(newBlock+i*cellSize, &nextAddress, ANC_SIZE);
}
메모리를 밀어주는 것 같은데, 방법을 다소 바꾸시면 불필요할듯해 보입니다.
memcpy(newBlock+i*cellSize, &nextAddress, ANC_SIZE); 에서 ANC_SIZE 의 경우 sizeof(void*) 인데,
Code: Select all
void* src = 뭔가 메모리 주소
void* dst = src;
newBlock + i*cell 보다는 블럭 구조체를 하나 만드셔서 포인터 연산하시는게 더 보기 좋습니다.
Code: Select all
byte*& nextFreeCell = nextFreeCellMap[size];
if (nextFreeCell == NOT_ASSIGNED ||
size >= OBJ_SIZE_LIMIT)
{ // This memory does not belong to the memory pool! (user mistake?)
::operator delete(pDeadObject); // Apply default delete operation.
return;
}
빗자루네 http://www.myevan.net >_<b
-
- Posts: 290
- Joined: 2006-07-10 02:25
myevan//
공용 메모리 풀이라고 했지만
완전히 공용으로 사용하는 풀은 아니고
오브젝트 사이즈 (sizeof(object)) 별로 전용 메모리 블럭을 할당하는 풀입니다.
예를 들어 16byte 오브젝트용 메모리 블럭은
MP_OBJ_PER_BLOCK * (링크포인터 크기(4byte) + 16byte) 의 크기를 가지고,
MP_OBJ_PER_BLOCK 개의 16byte 오브젝트를 담을 수 있다는 식입니다.
다른 크기의 오브젝트를 위해서는 또다른 블럭이 생성됩니다.
따라서 정해진 사이즈의 블럭 구조체를 만들 수는 없었던 거죠.
항상 거기에 담을 객체의 사이즈에 비례하니까요.
(저도 + * 연산자로 포인터 연산하는거 굉장히 싫어합니다만 공교롭게도 이 경우에는 이게 제일 적합하더군요)
class A, B, C 등이 존재하고 각각의 사이즈가 서로 다를 때,
현재의 알고리즘에서는
갖가지 클래스들을 짬뽕으로 new/delete 하더라도
같은 클래스 사이에는 메모리 갭이 생기지 않습니다 블럭이 서로 다르니까요.
물론 사이즈가 서로 같은 클래스끼리는 같은 블럭을 공유하기 때문에
동일 클래스 기준으로 갭이 생길 수 있습니다.
기왕이면 사이즈 기준으로 하지 말고
말씀처럼 클래스마다 블럭을 분류해주면 더 좋은 성능이 나오겠지만
만약 사이즈가 작은 클래스끼리 블럭이 공유된다면 생각만큼 큰 갭이 생기지 않고
사이즈가 큰 클래스끼리는 둘의 사이즈가 동일할 확률이 떨어진다는 점,
(또한 사이즈가 큰 클래스를 여러번 new/delete하는 경우는 적다는 점)
그리고 클래스마다 분류하기 위해서는 현재의 단순한 인터페이스(MemoryPooled 상속으로 사용)를
포기해야 한다는 점에 착안해서 설계했습니다.
그리고 블럭 구조체가 없는 것과 같은 이유로 셀 구조체도 없기 때문에
링크포인터 영역을 따로 읽고 쓰기 위해서 memcpy 를 사용하게 되었습니다.
역시 공용으로 만들기 위해서는 참 많은 가독성을 희생하게 되더군요..
만들던 저도 헷갈릴 정도였는데 일단 쓰기 쉬운 풀을 만들겠다는 일념 하나로 버텼죠.
여기까지 이론 답변이었고 오버플로우 지적 감사합니다.
공용 메모리 풀이라고 했지만
완전히 공용으로 사용하는 풀은 아니고
오브젝트 사이즈 (sizeof(object)) 별로 전용 메모리 블럭을 할당하는 풀입니다.
예를 들어 16byte 오브젝트용 메모리 블럭은
MP_OBJ_PER_BLOCK * (링크포인터 크기(4byte) + 16byte) 의 크기를 가지고,
MP_OBJ_PER_BLOCK 개의 16byte 오브젝트를 담을 수 있다는 식입니다.
다른 크기의 오브젝트를 위해서는 또다른 블럭이 생성됩니다.
따라서 정해진 사이즈의 블럭 구조체를 만들 수는 없었던 거죠.
항상 거기에 담을 객체의 사이즈에 비례하니까요.
(저도 + * 연산자로 포인터 연산하는거 굉장히 싫어합니다만 공교롭게도 이 경우에는 이게 제일 적합하더군요)
class A, B, C 등이 존재하고 각각의 사이즈가 서로 다를 때,
현재의 알고리즘에서는
갖가지 클래스들을 짬뽕으로 new/delete 하더라도
같은 클래스 사이에는 메모리 갭이 생기지 않습니다 블럭이 서로 다르니까요.
물론 사이즈가 서로 같은 클래스끼리는 같은 블럭을 공유하기 때문에
동일 클래스 기준으로 갭이 생길 수 있습니다.
기왕이면 사이즈 기준으로 하지 말고
말씀처럼 클래스마다 블럭을 분류해주면 더 좋은 성능이 나오겠지만
만약 사이즈가 작은 클래스끼리 블럭이 공유된다면 생각만큼 큰 갭이 생기지 않고
사이즈가 큰 클래스끼리는 둘의 사이즈가 동일할 확률이 떨어진다는 점,
(또한 사이즈가 큰 클래스를 여러번 new/delete하는 경우는 적다는 점)
그리고 클래스마다 분류하기 위해서는 현재의 단순한 인터페이스(MemoryPooled 상속으로 사용)를
포기해야 한다는 점에 착안해서 설계했습니다.
그리고 블럭 구조체가 없는 것과 같은 이유로 셀 구조체도 없기 때문에
링크포인터 영역을 따로 읽고 쓰기 위해서 memcpy 를 사용하게 되었습니다.
역시 공용으로 만들기 위해서는 참 많은 가독성을 희생하게 되더군요..
만들던 저도 헷갈릴 정도였는데 일단 쓰기 쉬운 풀을 만들겠다는 일념 하나로 버텼죠.
여기까지 이론 답변이었고 오버플로우 지적 감사합니다.
-
- Posts: 1314
- Joined: 2003-03-04 10:21
- Contact:
공용을 위해 가독성을 포기하고 작성하셨다면
한번 특화된 형태로 가독성 높게 작성해보세요
그 다음에 다시 공용으로 만들어 보시면 좀 더 다른 코드 모양이 되어있을 것입니다 : )
한번 특화된 형태로 가독성 높게 작성해보세요
그 다음에 다시 공용으로 만들어 보시면 좀 더 다른 코드 모양이 되어있을 것입니다 : )
빗자루네 http://www.myevan.net >_<b
-
- Posts: 290
- Joined: 2006-07-10 02:25
우움.. 사실 제가 제일 좋아하는 단어가 가독성인데
이렇게 완전 최말단 모듈인데다가 클래스는 커녕 자료형 개념조차 써먹을 수 없는 구석기시대같은 상황에서는
가독성을 유지할 방안이 안보이네요.
하필 속도가 생명인 부분이라 평소처럼 알기쉽게만 짜다보니 팍팍 느려지고..
확실히 루틴이 하위레벨로 들어갈수록 가독성 유지하기가 힘들다는 걸 느꼈습니다.
(단순히 변수이름 잘 정하는 정도의 의미는 아닙니다.)
괜히 서버 프로그래머는 C를 좋아하고 클라이언트 프로그래머는 C++를 좋아하는게 아닌 듯..
혹여나 제 것과 똑같은 일을 하면서 가독성도 훨씬 높은 코드를 짜는 사람을 본다면
사부로 모시던지 해야겠습니다.
이렇게 완전 최말단 모듈인데다가 클래스는 커녕 자료형 개념조차 써먹을 수 없는 구석기시대같은 상황에서는
가독성을 유지할 방안이 안보이네요.
하필 속도가 생명인 부분이라 평소처럼 알기쉽게만 짜다보니 팍팍 느려지고..
확실히 루틴이 하위레벨로 들어갈수록 가독성 유지하기가 힘들다는 걸 느꼈습니다.
(단순히 변수이름 잘 정하는 정도의 의미는 아닙니다.)
괜히 서버 프로그래머는 C를 좋아하고 클라이언트 프로그래머는 C++를 좋아하는게 아닌 듯..
혹여나 제 것과 똑같은 일을 하면서 가독성도 훨씬 높은 코드를 짜는 사람을 본다면
사부로 모시던지 해야겠습니다.
-
- Posts: 1314
- Joined: 2003-03-04 10:21
- Contact:
퇴근하고 여친 만나러 가는 길에 심심해서 한번 만들어 봤습니다 : )
조건이 "1024 크기 미만의 메모리만 풀링을 한다" 만 지키면 되는지요?
(코드내 vector 를 이미 쓰셨길래 똑같이 vector 를 썼습니다; )
급하게 짠거라 버그가 있을지 모르겠습니다만 : )
아래는 테스트 프로그램입니다
결과
MemoryPooled virtual 파괴자가 없어서 추가했더니 경고가 몇개 나는군요;
조건이 "1024 크기 미만의 메모리만 풀링을 한다" 만 지키면 되는지요?
(코드내 vector 를 이미 쓰셨길래 똑같이 vector 를 썼습니다; )
급하게 짠거라 버그가 있을지 모르겠습니다만 : )
Code: Select all
#include <vector>
#include <algorithm>
class MemoryPool
{
public:
enum
{
ALLOC_MAX_SIZE = 1024,
};
public:
~MemoryPool()
{
std::for_each(m_dataVector.begin(), m_dataVector.end(), free);
}
void* Alloc(int size)
{
if (size >= ALLOC_MAX_SIZE)
{
void* ret = malloc(size);;
printf("::new\t%p:%d\n", ret, size);
return ret;
}
std::vector<void*>& freeVector = m_freeVector[size];
if (!freeVector.empty())
{
void* ret = freeVector.back();
freeVector.pop_back();
printf("reuse\t%p:%d\n", ret, size);
return ret;
}
void* ret = malloc(size);
m_dataVector.push_back(ret);
printf("new\t%p:%d\n", ret, size);
return ret;
}
void Free(void* ptr, int size)
{
if (size >= ALLOC_MAX_SIZE)
{
printf("::free\t%p:%d\n", ptr, size);
free(ptr);
return;
}
printf("free\t%p:%d\n", ptr, size);
std::vector<void*>& freeVector = m_freeVector[size];
freeVector.push_back(ptr);
}
private:
std::vector<void*> m_dataVector;
std::vector<void*> m_freeVector[ALLOC_MAX_SIZE];
};
class MemoryPooled
{
public:
virtual ~MemoryPooled() {}
void* operator new(size_t size)
{
return s_pool.Alloc(size);
}
void operator delete(void* obj, size_t size)
{
s_pool.Free(obj, size);
}
private:
static MemoryPool s_pool;
};
MemoryPool MemoryPooled::s_pool;
Code: Select all
class A : public MemoryPooled {
};
struct B : MemoryPooled {
char c;
};
struct C : MemoryPooled {
short c;
};
class D : public MemoryPooled {
public:
virtual ~D() {}
char buf[100];
};
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <assert.h>
#define New(T) test.push_back(new T);
#define Pop() {delete test.back();test.pop_back();}
#define Del(i) {delete test[i];test.erase(test.begin()+i);}
#define NewChk(T, V) {T* o = new T; o->c = V;test.push_back(o);}
#define PopChk(T, V) {T* o = (T*)test.back();printf("%d\n", o->c);assert(o->c == V);delete test.back();test.pop_back();}
int main(int argc, char* argv[])
{
{
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
}
std::vector<MemoryPooled*> test;
New(A)
Pop()
NewChk(B, 1)
NewChk(B, 2)
New(C)
New(D)
Pop()
Pop()
PopChk(B, 2)
PopChk(B, 1)
return 0;
}
ps.new 00370FE0:4
free 00370FE0:4
new 003710C0:8
new 00371018:8
new 00371050:8
new 003711C0:104
free 003711C0:104
free 00371050:8
2
free 00371018:8
1
free 003710C0:8
MemoryPooled virtual 파괴자가 없어서 추가했더니 경고가 몇개 나는군요;
delete(ptr, size); 형태는 첨이라;; 관련 내용은 밥먹고 심심해지면 추가하겠습니다.C:\libs\utils\mem_pool\mem_pool.cpp(124) : warning C4291: 'void *__cdecl MemoryPooled::operator new(unsigned int)' : no matching operator delete found; memory will not be freed if initialization throws an exception
C:\libs\utils\mem_pool\mem_pool.cpp(70) : see declaration of 'new'
빗자루네 http://www.myevan.net >_<b
-
- Posts: 290
- Joined: 2006-07-10 02:25
조건은
0. 제 풀의 소스보다 가독성이 뛰어나야 합니다.
1. size가 1024byte 미만인 클래스/구조체에 대한 메모리만 풀링을 합니다.
2. new [], delete [] 에 대해서는 풀링하지 않습니다.
3. MemoryPooled 를 상속하는 것만으로 사용할 수 있어야 합니다.
4. 여러 클래스에 대한 마구잡이 new/delete를 했을 때 소모시간이 제가 만든 풀보다 적거나 같아야 합니다.
5. C/C++ 표준에 있는 어느 문법이든 사용하실 수 있습니다. (STL 포함)
0번은 이 문제가 나온 목적이니 지켜져야 하는데, 여기서 걸릴 분은 없을듯 ^^;;
1번은 안 중요하고
2번은 별 상관 없고
3번이 중요하고
4번은 더 중요합니다.
메모리 풀을 쓰는 이유는 메모리 단편화를 막기 위해서고,
그걸 막으려는 가장 큰 이유가 바로 속도 때문이니까요(적어도 게임에서는요).
이 속도가 바로 가독성을 날려먹는 주범이기도 하죠.
5번은 제약조건이 아닙니다.
문법상의 제약이 없다는 뜻인데, STL이 결코 느린 구현물이 아니지만
지금 만드려는 것은 메모리에 직접 접근하는 메모리 풀이니까 나름 고민해가면서 써야겠죠.
다음은 테스트용 코드입니다.
테스트 사이즈 n을 주면
사이즈가 다른 3개의 클래스로 일부러 메모리 조각내기를 시도하면서
n제곱에 비례하는 new/delete를 먹인 후 총 경과시간을 체크해줍니다.
srand(0) 을 먹였으니까 항상 같은 패턴의 테스트를 보장해줍니다.
http://blogfile.paran.com/BLOG_335916/2 ... olTest.zip
테스트 결과는 이렇습니다.
경과시간:
Pool by Remisa < default new/delete < Pool by myevan
(물론 printf 는 지우고 테스트했습니다.)
즉 4번 조건을 충족시키지 못하셨습니다.
0. 제 풀의 소스보다 가독성이 뛰어나야 합니다.
1. size가 1024byte 미만인 클래스/구조체에 대한 메모리만 풀링을 합니다.
2. new [], delete [] 에 대해서는 풀링하지 않습니다.
3. MemoryPooled 를 상속하는 것만으로 사용할 수 있어야 합니다.
4. 여러 클래스에 대한 마구잡이 new/delete를 했을 때 소모시간이 제가 만든 풀보다 적거나 같아야 합니다.
5. C/C++ 표준에 있는 어느 문법이든 사용하실 수 있습니다. (STL 포함)
0번은 이 문제가 나온 목적이니 지켜져야 하는데, 여기서 걸릴 분은 없을듯 ^^;;
1번은 안 중요하고
2번은 별 상관 없고
3번이 중요하고
4번은 더 중요합니다.
메모리 풀을 쓰는 이유는 메모리 단편화를 막기 위해서고,
그걸 막으려는 가장 큰 이유가 바로 속도 때문이니까요(적어도 게임에서는요).
이 속도가 바로 가독성을 날려먹는 주범이기도 하죠.
5번은 제약조건이 아닙니다.
문법상의 제약이 없다는 뜻인데, STL이 결코 느린 구현물이 아니지만
지금 만드려는 것은 메모리에 직접 접근하는 메모리 풀이니까 나름 고민해가면서 써야겠죠.
다음은 테스트용 코드입니다.
테스트 사이즈 n을 주면
사이즈가 다른 3개의 클래스로 일부러 메모리 조각내기를 시도하면서
n제곱에 비례하는 new/delete를 먹인 후 총 경과시간을 체크해줍니다.
srand(0) 을 먹였으니까 항상 같은 패턴의 테스트를 보장해줍니다.
http://blogfile.paran.com/BLOG_335916/2 ... olTest.zip
테스트 결과는 이렇습니다.
경과시간:
Pool by Remisa < default new/delete < Pool by myevan
(물론 printf 는 지우고 테스트했습니다.)
즉 4번 조건을 충족시키지 못하셨습니다.
Last edited by Remisa on 2006-12-18 22:28, edited 4 times in total.
뭐하자는 건지..-_-
[인용]"즉 4번 조건을 충족시키지 못하셨습니다."
도데체 뭐하자는 건지요...
메모리풀 같은것들 인터넷 두둘기면 풀소스 통째로 있습니다.
요즘세상에 인터넷이 자료실인데 뭐가 없겠습니까..
메모리풀이던 뭐던 만들었으면 그냥 본인만 쓰세요..
만들고 나니 기쁘고 공개하고 싶은 마음은 이해하지만...
이건좀 아닌것 같네요..
도데체 뭐하자는 건지요...
메모리풀 같은것들 인터넷 두둘기면 풀소스 통째로 있습니다.
요즘세상에 인터넷이 자료실인데 뭐가 없겠습니까..
메모리풀이던 뭐던 만들었으면 그냥 본인만 쓰세요..
만들고 나니 기쁘고 공개하고 싶은 마음은 이해하지만...
이건좀 아닌것 같네요..
-
- Posts: 290
- Joined: 2006-07-10 02:25
Re: 뭐하자는 건지..-_-
어익후 이거 죄송해서 어쩌죠..비회원 wrote:[인용]"즉 4번 조건을 충족시키지 못하셨습니다."
도데체 뭐하자는 건지요...
메모리풀 같은것들 인터넷 두둘기면 풀소스 통째로 있습니다.
요즘세상에 인터넷이 자료실인데 뭐가 없겠습니까..
메모리풀이던 뭐던 만들었으면 그냥 본인만 쓰세요..
만들고 나니 기쁘고 공개하고 싶은 마음은 이해하지만...
이건좀 아닌것 같네요..
-
- Posts: 1314
- Joined: 2003-03-04 10:21
- Contact:
흑 (-_-); 설마 결과가 왜 그렇게 나온건지 모르고 쓰신건 아니실테지만...
다소 흥분하신 상태에서 그런거라 생각하고...
vector 로 구현했으니; 적당한 크기로 reserve 해주면 속도가 빨라집니다.
이렇게 변경 하고 다시 테스트하면 거의 비슷한 속도가 납니다.
참고로 제가 좋아하는 풀은 아래와 같은 형태입니다.
http://www.myevan.net/phpBB/viewtopic.p ... MemoryPool
대부분 정적인 메모리를 사용해서 지역성을 높이고, 할당 한계를 넘어서면 자동으로 동적으로 메모리할당을 하게 합니다.
물론 공유 되지는 않습니다. 전 공유되는 메모리 풀은 별로 안 좋아하거든요 : )
개인적으로 자기가 작성한 코드를 공개하는 일은 좋다고 생각합니다.
평가 받는 다는건 쉬운 일이 아니거든요;; (= =)~
반가운 마음에 그냥 좀 더 개선할 수 있는 방향이 있다라는 점에서 이야기드린건데 기분이 상하셨던 것 같내요 : )
다소 흥분하신 상태에서 그런거라 생각하고...
Code: Select all
MemoryPool2()
{
for (int i = 0; i != ALLOC_MAX_SIZE; ++i)
m_freeVector[i].reserve(100*1024); // 사이즈는 적당히 잡아주세요
m_dataVector.reserve(100*1024); // 사이즈는 적당히 잡아주세요
}
이렇게 변경 하고 다시 테스트하면 거의 비슷한 속도가 납니다.
참고로 제가 좋아하는 풀은 아래와 같은 형태입니다.
http://www.myevan.net/phpBB/viewtopic.p ... MemoryPool
대부분 정적인 메모리를 사용해서 지역성을 높이고, 할당 한계를 넘어서면 자동으로 동적으로 메모리할당을 하게 합니다.
물론 공유 되지는 않습니다. 전 공유되는 메모리 풀은 별로 안 좋아하거든요 : )
개인적으로 자기가 작성한 코드를 공개하는 일은 좋다고 생각합니다.
평가 받는 다는건 쉬운 일이 아니거든요;; (= =)~
반가운 마음에 그냥 좀 더 개선할 수 있는 방향이 있다라는 점에서 이야기드린건데 기분이 상하셨던 것 같내요 : )
빗자루네 http://www.myevan.net >_<b
-
- Posts: 3805
- Joined: 2001-07-25 09:00
- Location: GPGstudy
- Contact:
Re: 뭐하자는 건지..-_-
만들었으면 공개, 공유하자는 게 GPG 시리즈의 취지이자 포럼의 취지이기도 합니다. Remisa님(및 회원분들), 이런 글은 대응하지 말고 무시하세요... 인용을 하면 지우기가 그렇거든요. (이 부분도 다시 생각 중입니다... 인용이 되었으므로 지워도 상관없지 않을까 하는...)비회원 wrote:[인용]"즉 4번 조건을 충족시키지 못하셨습니다."
도데체 뭐하자는 건지요...
메모리풀 같은것들 인터넷 두둘기면 풀소스 통째로 있습니다.
요즘세상에 인터넷이 자료실인데 뭐가 없겠습니까..
메모리풀이던 뭐던 만들었으면 그냥 본인만 쓰세요..
만들고 나니 기쁘고 공개하고 싶은 마음은 이해하지만...
이건좀 아닌것 같네요..
-
- Posts: 59
- Joined: 2004-06-01 09:36
- Location: 게임공장
-
- Posts: 1314
- Joined: 2003-03-04 10:21
- Contact:
앗 -ㅅ-);; 어떤 분이 궁금증 올려서 답변을 만들었는데...
글이 사라졌군요;
vc6 컴파일 후 실행 결과는 이렇습니다.
만약 어떤 프로그램이 메모리 풀을 사용하지 않고
new/delete 를 반복한다면 드문드문 메모리가 할당되게 됩니다.
지역성 중요성에 대한 주요 사례는
최적화에 너무 집중해서 가독성을 떨어뜨리는건 좋지 않지만
엇비슷한 가독성을 유지할 수 있다면 최적화 습관이나 이론적 지식은 가지고 있는 것이 좋습니다 : )
글이 사라졌군요;
Code: Select all
#include <stdio.h>
int main()
{
char* p1 = new char[16];
printf("p1 %p\n", p1);
char* p2 = new char[16];
printf("p2 %p\n", p2);
char* p3 = new char[16];
printf("p3 %p\n", p3);
char* p4 = new char[16];
printf("p4 %p\n", p4);
char* p5 = new char[16];
printf("p5 %p\n", p5);
delete p2;
delete p4;
// 여기서 만약 메모리 풀 메모리를 할당한다고 생각하면...
char* p6 = new char[16];
printf("p6 %p\n", p6);
delete p5;
delete p3;
delete p1;
return 0;
}
p6 번은 p4 메모리가 재사용되고 있습니다.p1 00370FE0
p2 00371028
p3 00371070
p4 003710B8
p5 00371100
p6 003710B8
만약 어떤 프로그램이 메모리 풀을 사용하지 않고
new/delete 를 반복한다면 드문드문 메모리가 할당되게 됩니다.
지역성 중요성에 대한 주요 사례는
등등이 있습니다.1. 속도 최적화보다 크기 최적화가 요즘에는 더 빠르다.
2. 멤버들을 개별적으로 메모리 할당한 구조보다 한번에 할당한 구조가 더 빠르다.3. 2와 비슷한 구조로 각 객체를 new 로 할당한 것보다 스택에 정적으로 선언한게 더 빠르다.Code: Select all
// #1 parent = new Parent; parent->children = new Child[100]; // #2: 이쪽이 더 빠릅니다. parent = malloc(sizeof(Parent) + sizeof(Child)*100)
4. python 은 메모리 풀 도입으로 상당한 성능 향상을 보았다. (물론 alloc/free 코스트와 겹쳐지겠죠; )
5. mem[x][y][z] 보다 mem[z][y][x] 가 더 빠르다.
최적화에 너무 집중해서 가독성을 떨어뜨리는건 좋지 않지만
엇비슷한 가독성을 유지할 수 있다면 최적화 습관이나 이론적 지식은 가지고 있는 것이 좋습니다 : )
빗자루네 http://www.myevan.net >_<b
-
- Posts: 35
- Joined: 2003-06-12 10:00
- Contact:
new, delete 대상?
1번 코드의 의도가 vector< Object *> objects가 가르키는 Object *를 직접 new, delete 할 경우를 의미하나요?myevan wrote:
#1#2Code: Select all
vector <Object *> objects; for (int i = 0; i != OBJ_NUM; ++i) objects.push_back(new Object); UseObjects(objects);
#1 과 #2 프로그램을 처음 실행할때는 성능은 거의 비슷합니다.Code: Select all
Object objects[OBJ_NUM]; UseObjects(objects);
하지만 오래동안 실행되서 다른 코드에서 new, delete 가 많이 사용한 이후에
#2 의 objects[0] 과 objects[1] 거리는 언제나 sizeof(Object) 만큼이지만
#1 의 *objects[0] 과 *objects[1] 거리는 sizeof(Object) 보다 대개 늘어나게 됩니다.
이 거리가 운영체제가 관리하는 페이지 크기보다 커지면 실행 속도에 상당한 악영향을 미치게 됩니다.
-
- Posts: 1314
- Joined: 2003-03-04 10:21
- Contact:
네 동적할당(#1) 이냐 정적할당(#2)이냐의 차이입니다.
요약하자면 정적할당과는 달리
동적할당은 프로그램 실행 시점에 따라 퍼포먼스의 변화가 생긴다라는 점을 이야기하고 싶었습니다.
요약하자면 정적할당과는 달리
동적할당은 프로그램 실행 시점에 따라 퍼포먼스의 변화가 생긴다라는 점을 이야기하고 싶었습니다.
빗자루네 http://www.myevan.net >_<b