직접 짠 malloc/free 최적화 도와주세요

denmark114의 이미지

얼마전 자유게시판에 C/Java 속도비교글 올렸던 사람입니다. 관련해서 올립니다.

자잘한 메모리 동적 할당을 아주 많이 하게될 프로젝트가 있습니다. 기가바이트 단위로 트리를 만들었다 지웠다 하면서 연산을 해야합니다. C로 짜지 않으면 안되겠다 했는데 테스트를 해 보니 MinGW/GCC에서 기본으로 제공하는 C 라이브러리의 malloc/free 함수가 너무 느린것 같습니다.

[코드 1]: C로 짠 테스트코드
[코드 2]: Java로 짠 테스트코드
[코드 3]: 직접 짠 malloc/free 함수

[코드 1]을 컴파일 할 때에 매크로 MJ_ALLOCATOR 를 정의해주면 제가 짠 malloc/free 함수를 대신 사용하게 됩니다. 지금 문제는 malloc/free함수의 성능이 기본버전이나 제가 짠 버전이나 Java의 메모리 관리자보다 많이 느립니다. 아래는 테스트 결과입니다.

운영체제: Windows 7

언어: C
malloc/free 라이브러리: 기본 (msvcrt?)
최적화옵션: -O3 -march=native
실행시간 (초): 120 +/- 1

언어: C
malloc/free 라이브러리: 자작
최적화옵션: -O3 -march=native
실행시간 (초): 24 +/- 1

언어: Java
실행시간 (초): 12 +/- 1

[코드 3]에서 조금이라도 속도를 빠르게 할수 있는 부분이 보인다면 도와주세요^^. 미리 감사합니다~

[코드 1]

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
#ifdef MJ_ALLOCATOR
#include "mj_allocator.h"
#endif
 
enum {ARRAY_LEN = 50000};
int *array[ARRAY_LEN];
long long sum = 0;
 
int confuse_the_compiler(int n)
{
	return n % 10 > 5 ? -n / 2 : n * 2;
}
 
void start()
{
	for (int i = 1; i <= ARRAY_LEN; ++i)
	{
		for (int j = 0; j < i; ++j)
		{
			array[j] = (int *)malloc(sizeof(int));
			array[j][0] = j + 1;
		}
		for (int j = i - 1; j >= 0; --j)
		{
			sum -= j;
			int n = confuse_the_compiler(array[j][0]);
			if (n != 0)
			{
				sum += n;
				free(array[j]);
			}
		}
	}
}
 
int main()
{
 
#ifdef MJ_ALLOCATOR
	use_mj_allocator(ARRAY_LEN * sizeof(int));
#endif
 
	time_t start_time = clock();
	start();
	time_t end_time = clock();
	printf("\nelapsed time: %.3f\n", (double)(end_time - start_time) / CLOCKS_PER_SEC);
	printf("%lld", sum);
 
#ifdef MJ_ALLOCATOR
	free_mj_allocator();
#endif
 
	return 0;
}

[코드 2]

class test
{
	final static int ARRAY_LEN = 50000;
	static int[][] array = new int[ARRAY_LEN][];
	static long sum = 0;
 
	static int confuse_the_compiler(int n)
	{
		return n % 10 > 5 ? -n / 2 : n * 2;
	}
 
	static void start()
	{
		for (int i = 1; i <= ARRAY_LEN; ++i)
		{
			for (int j = 0; j < i; ++j)
			{
				array[j] = new int[1];
				array[j][0] = j + 1;
			}
			for (int j = i - 1; j >= 0; --j)
			{
				sum -= j;
				int n = confuse_the_compiler(array[j][0]);
				if (n != 0)
				{
					sum += n;
					// free(array[j]);
				}
			}
		}
	}
 
	public static void main(String[] args)
	{
		long start_time = System.currentTimeMillis();
		start();
		System.gc();
		long end_time = System.currentTimeMillis();
		System.out.printf("\nelapsed time: %.3f\n", (end_time - start_time) / 1000.0);
		System.out.println(sum);
	}
}

[코드 3]
첨부파일 :)

File attachments: 
첨부파일 크기
Package icon mj_allocator.zip1.17 KB
익명 사용자의 이미지

denmark114의 이미지

해당 documentation을 읽어보았을땐 arena_t 오브젝트에 메모리 주소를 모아두었다 한번에 해제하는 방식인것 같은데요, 지금같은 경우는 프로그램 중간중간에 메모리를 일부분씩 free해주는 기능이 꼭 필요합니다.

kukyakya의 이미지

메모리 할당자를 직접 짜시는건 그닥 좋은 방법이 아닌것 같습니다. 잘 짜기도 어려울 뿐더러, 기존의 구현체에 비해 좋은 성능을 내기 쉽지 않습니다.

tcmalloc등의 구현체를 사용하시면 코드를 바꾸지 않고도 적용이 가능합니다.

올려주신 코드의 성능 차이는 아마도 malloc/free와 java 메모리할당자의 차이로 인한 것으로 생각합니다.

http://programmers.stackexchange.com/questions/208656/java-heap-allocation-faster-than-c 의 답변을 참고하시면 될 것 같습니다.

simminjo의 이미지

이런것도 있었군요......역시...구글..........입니다...

---------------------------------------------------------------
Opensource에 기여하는 것이 꿈입니다.
내가 만든 코드를 모두가 사용할 때 까지~

ymir의 이미지

직접 프로파일링 해볼 수 있는 머신이 없는 상태라.. 그냥 떠오르는 생각 몇 개 적어 봅니다.
어차피 필요한 만큼의 메모리는 반드시 확보되어야 한다는 전제는 변하지 않으니..;;

alloc/free 가 빈번하다면.. alloc 비용은 어쩔 수 없다 쳐도.. free 는 굳이 할 필요가..;;
free list 를 하나 만들어서 list 의 head 가 null 일 때에만 alloc 하고.. free 할 때에는 head 에 insert ..

같은 함수 내에서 alloc/free 를 반복하는 경우라면..
static 으로 잡아서 free 하지 말고 필요한 경우에만 realloc .. (capacity 는 x2 로 증가)

1k 대신 kib 단위로(2^n 사용).. x1024 면 <<10 으로 알아서 최적화 될겁니다..

어차피 최대 갯수가 정해져 있다면, 그거 한꺼번에 통으로 alloc "한 번" 해서.. array 나 list 로 쪼개서 쓰기..
alloc/free list 만 관리하면 굳이 free 호출할 필요 없죠.

최대 갯수가 가변이거나.. 한번 alloc 할 때 fail 떨어질 가능성이 있을 정도로 사이즈가 크면..
일정 갯수 만큼 한 번에 alloc 해서 available list 에 추가해도 되겠죠.

끝으로.. list alloc 비용은? 할 수 있는데..
애초부터 list emelment 단위로 alloc 하고 그 안에 list ptr 와 실제 buffer 를 둡니다..

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

simminjo의 이미지

버디 알고리즘 이라는 녀석을 한번 참고해보시죠?
아마도 도움이 되실 듯 합니다.

흔히 운영체제 책에서 말하는 요청한 사이즈에 적당한 공간을 찾기위한 서칭에서 많은 시간이 소모 됩니다.
또 이것이 내/외부 단편화라는 것과도 영향이 있지요.....

기본 malloc은 성능이 매우 좋지 못한것으로 알고있습니다.( 제 기억에는 말이죠.. )

---------------------------------------------------------------
Opensource에 기여하는 것이 꿈입니다.
내가 만든 코드를 모두가 사용할 때 까지~

kukyakya의 이미지

기본 malloc의 성능이 구리다는 편견이 있긴 하나 실제로는 굉장히 좋은 편입니다. 다만 일반적인 상황에서의 사용을 고려해야하기 때문에 특정 환경에서는 다소 성능이 떨어질 수 있습니다.

일정 이상의 퍼포먼스가 필요하면 단편화, 탐색시간, 캐시 등등을 고려하여 사용할 코드의 특성에 가장 알맞는 구현체를 찾아 사용하는것이 바람직합니다.

익명 사용자의 이미지

꼭 C로 짤 필요없으면, Java로 하면 안되나요?
저도 C와 C++가 모국어지만, 생산성 측면에서 봐야지 언어를 고집해야할 이유가 없을 것 같은데요?

IsExist의 이미지

저렇게 작은 사이즈로 빈번하게 할당하고 해제하는 경우는 java 가 빠를 수 밖에 없습니다.
C 에서는 해제 호출시 실제 해제 코드를 타고 해제가 이루어집니다.
java는 더 이상 참조가 이루어지지 않으면 가비지 콜렉터가 실행되겠죠.

할당도 위한 같은 상황이 발생할 수 있는게 C는 작은 사이즈를 할당을
호출할때마다 할당을 합니다. java 는 jvm 내에서 이를 최적화할 수 있죠.
예를 들어 크게 한번 할당하고 그 공간을 나중에 쪼개서 할당할 수 있겠죠.

C 로도 이런 비슷한 전략을 사용할 수 있습니다. ymir 님이 설명한게
그런 형태입니다.
일종의 메모리 풀 전략으로 가면 됩니다. 해제시는 실제 해제를 하는게 아니라
freed_list 목록에 넣어 두는거죠. 할당때는 저기서 빈것을 가져와서
할당합니다.

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.