为什么 slice allocator 在 glib2.0 中比 malloc 慢?
Why slice allocator is slower than malloc in glib2.0?
我写了两个简单的程序来比较g_slice_alloc()和g_malloc()[=49=的速度].
g_slice_alloc()版本:
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
gchar *mem[1000000];
gint i;
for(i=0;i<1000000;i++){
mem[i]=g_slice_alloc(50);
}
for(i=0;i<1000000;i++){
g_slice_free1(50,mem[i]);
}
return 0;
}
和g_malloc()版本
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
gchar *mem[1000000];
gint i;
for(i=0;i<1000000;i++){
mem[i]=g_malloc(50);
}
for(i=0;i<1000000;i++){
g_free(mem[i]);
}
return 0;
}
编译它们
gcc slice.c -o slice `pkg-config --libs --cflags gtk+-3.0`
gcc malloc.c -o malloc `pkg-config --libs --cflags gtk+-3.0`
并测试它们
$ time ./slice
real 0m0.091s
user 0m0.063s
sys 0m0.025s
$ time ./malloc
real 0m0.071s
user 0m0.050s
sys 0m0.021s
g_slice_alloc() 版本预计 运行 更快,但实际上并非如此。为什么它更慢?
这是一个很好的测试用例吗?
然后我尝试了另一种方法来测试他们的速度。
#include <gtk/gtk.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
gchar *mem[1000000];
gint i;
for(i=0;i<1000000;i++){
gint j=i>10000?10000:i;
mem[i]=g_slice_alloc(j);
}
for(i=0;i<1000000;i++){
gint j=i>10000?10000:i;
g_slice_free1(j,mem[i]);
}
return 0;
}
#include <gtk/gtk.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
gchar *mem[1000000];
gint i;
for(i=0;i<1000000;i++){
gint j=i>10000?10000:i;
mem[i]=g_malloc(j);
}
for(i=0;i<1000000;i++){
gint j=i>10000?10000:i;
g_free(mem[i]);
}
return 0;
}
这次他们真的很接近,有时g_slice_alloc()更快,有时g_malloc() 更快。
$ time ./malloc
real 0m1.515s
user 0m0.285s
sys 0m1.229s
$ time ./slice
real 0m1.521s
user 0m0.278s
sys 0m1.215s
但是这个测试并不能证明g_slice_alloc()更快,它只是说明g_slice_alloc() 等同于 g_malloc()
glibc
的 malloc 改进了 很多 自从添加 GSlice
以来(当时 glibc 的 malloc 非常慢)。 GSlice 过去比 malloc 快很多,但由于 malloc 中的积极优化,它现在更快了,特别是对于线程繁重的应用程序。同时,GSlice
自添加以来并没有真正发生重大变化。
AFAIK,如今使用 GSlice
的唯一真正原因是它在不同平台上更加稳定(例如,显然 Windows' malloc 对于 GStreamer 来说太慢了)。
综上所述,您上面的内容并不是一个很好的测试。像 GSlice
这样的平板式分配器传统上擅长减少内存碎片,这是由许多不同大小的 allocations/frees 混合在一起引起的。您拥有的是一堆分配,然后是一堆释放。
此外,像 GSlice
这样的分配器依赖于相同大小的分配,因此增加分配大小的测试部分不会很好地工作——GSlice
是针对对象的,不是字符串和缓冲区。
我写了两个简单的程序来比较g_slice_alloc()和g_malloc()[=49=的速度].
g_slice_alloc()版本:
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
gchar *mem[1000000];
gint i;
for(i=0;i<1000000;i++){
mem[i]=g_slice_alloc(50);
}
for(i=0;i<1000000;i++){
g_slice_free1(50,mem[i]);
}
return 0;
}
和g_malloc()版本
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
gchar *mem[1000000];
gint i;
for(i=0;i<1000000;i++){
mem[i]=g_malloc(50);
}
for(i=0;i<1000000;i++){
g_free(mem[i]);
}
return 0;
}
编译它们
gcc slice.c -o slice `pkg-config --libs --cflags gtk+-3.0`
gcc malloc.c -o malloc `pkg-config --libs --cflags gtk+-3.0`
并测试它们
$ time ./slice
real 0m0.091s
user 0m0.063s
sys 0m0.025s
$ time ./malloc
real 0m0.071s
user 0m0.050s
sys 0m0.021s
g_slice_alloc() 版本预计 运行 更快,但实际上并非如此。为什么它更慢?
这是一个很好的测试用例吗?
然后我尝试了另一种方法来测试他们的速度。
#include <gtk/gtk.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
gchar *mem[1000000];
gint i;
for(i=0;i<1000000;i++){
gint j=i>10000?10000:i;
mem[i]=g_slice_alloc(j);
}
for(i=0;i<1000000;i++){
gint j=i>10000?10000:i;
g_slice_free1(j,mem[i]);
}
return 0;
}
#include <gtk/gtk.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
gchar *mem[1000000];
gint i;
for(i=0;i<1000000;i++){
gint j=i>10000?10000:i;
mem[i]=g_malloc(j);
}
for(i=0;i<1000000;i++){
gint j=i>10000?10000:i;
g_free(mem[i]);
}
return 0;
}
这次他们真的很接近,有时g_slice_alloc()更快,有时g_malloc() 更快。
$ time ./malloc
real 0m1.515s
user 0m0.285s
sys 0m1.229s
$ time ./slice
real 0m1.521s
user 0m0.278s
sys 0m1.215s
但是这个测试并不能证明g_slice_alloc()更快,它只是说明g_slice_alloc() 等同于 g_malloc()
glibc
的 malloc 改进了 很多 自从添加 GSlice
以来(当时 glibc 的 malloc 非常慢)。 GSlice 过去比 malloc 快很多,但由于 malloc 中的积极优化,它现在更快了,特别是对于线程繁重的应用程序。同时,GSlice
自添加以来并没有真正发生重大变化。
AFAIK,如今使用 GSlice
的唯一真正原因是它在不同平台上更加稳定(例如,显然 Windows' malloc 对于 GStreamer 来说太慢了)。
综上所述,您上面的内容并不是一个很好的测试。像 GSlice
这样的平板式分配器传统上擅长减少内存碎片,这是由许多不同大小的 allocations/frees 混合在一起引起的。您拥有的是一堆分配,然后是一堆释放。
此外,像 GSlice
这样的分配器依赖于相同大小的分配,因此增加分配大小的测试部分不会很好地工作——GSlice
是针对对象的,不是字符串和缓冲区。