简体   繁体   English

如何减少默认的C ++内存消耗?

[英]How to reduce default C++ memory consumption?

I have a server application written in C++. 我有一个用C ++编写的服务器应用程序。 After startup, it uses about 480 KB of memory on x86 Linux (Ubuntu 8.04, GCC 4.2.4). 启动后,它在x86 Linux上使用大约480 KB的内存(Ubuntu 8.04,GCC 4.2.4)。 I think 480 KB is an excessive amount of memory: the server isn't even doing anything yet, no clients have been connected to the server. 我认为480 KB是一个过多的内存:服务器甚至没有做任何事情,没有客户端连接到服务器。 (See also my comment below in which I explain why I think 480 KB is a lot of memory.) The only things the server does during initialization is spawning one or two threads, setting up a few sockets, and other simple things that aren't very memory-intensive. (另请参阅下面的评论,其中我解释了为什么我认为480 KB是大量内存。)服务器在初始化期间唯一做的事情就是产生一个或两个线程,设置几个套接字,以及其他简单的东西。非常记忆密集。

Note that I'm talking about real memory usage, not VM size. 请注意,我在谈论实际内存使用情况,而不是VM大小。 I measured it by starting 100 instances of my server on an idle laptop and measuring the system memory usage with 'free' before and after starting the server instances. 我通过在空闲笔记本电脑上启动我的服务器的100个实例来测量它,并在启动服务器实例之前和之后用“免费”测量系统内存使用情况。 I've already taken filesystem cache and things like that into account. 我已经考虑了文件系统缓存和类似的东西。

After some testing it would appear that something in the C++ runtime is causing my server to use this much memory even if the server itself doesn't do anything. 经过一些测试后,看起来C ++运行时中的某些东西会导致我的服务器使用这么多内存,即使服务器本身没有做任何事情。 For example, if I insert 例如,如果我插入

getchar(); return 0;

right after 之后

int main(int argc, char *argv[]) {

then the memory usage is still 410 KB per instance! 然后每个实例的内存使用量仍为410 KB!

My application depends only on Curl and Boost. 我的应用程序仅依赖于Curl和Boost。 I have a fair amount of experience with C programming and I know C libraries don't tend to increase memory consumption until I use them. 我有很多C编程经验,我知道C库在使用之前不会增加内存消耗。

Other things that I've found: 我发现的其他事情:

  • A simple hello world C app consumes about 50 KB of memory. 一个简单的hello world C app消耗大约50 KB的内存。
  • A simple hello world C app linked to Curl, but otherwise not using Curl, consumes about 50 KB of memory as well. 一个简单的hello world C app链接到Curl,但不使用Curl,也消耗大约50 KB的内存。
  • A simple hello world C++ app (no Boost) consumes about 100 KB of memory. 一个简单的hello world C ++应用程序(没有Boost)消耗大约100 KB的内存。
  • A simple hello world C++ app that includes some Boost headers, but does not actually use Boost, consumes about 100 KB of memory. 一个简单的hello world C ++应用程序包含一些Boost标头,但实际上并没有使用Boost,它消耗大约100 KB的内存。 No Boost symbols when inspecting the executable with 'nm'. 使用'nm'检查可执行文件时没有Boost符号。

My conclusion is therefore as follows: 我的结论如下:

  1. Gcc throws away unused Boost symbols. Gcc抛弃了未使用的Boost符号。
  2. If my app uses Boost, then something in the C++ runtime (probably the dynamic linker) causes it to use a lot of memory. 如果我的应用程序使用Boost, 那么C ++运行时(可能是动态链接器)中的某些内容会导致它使用大量内存。 But what? 但是什么? How do I find out what these things are, and what can I do about them? 我怎样才能知道这些东西是什么,我能对它们做些什么?

I remember some KDE discussions several years ago about C++ dynamic linker issues. 我记得几年前关于C ++动态链接器问题的一些KDE讨论。 The Linux C++ dynamic linker back then caused slow startup time in KDE C++ apps and large memory consumption. 之后的Linux C ++动态链接器导致KDE C ++应用程序启动时间慢,内存消耗大。 As far as I know those issues have since been fixed in C++ runtimes. 据我所知,这些问题已在C ++运行时修复。 But could something similar be the cause of the excessive memory consumption I'm seeing? 但类似的东西可能是我所看到的过度记忆消耗的原因吗?

Answers from gcc/dynamic linking experts are greatly appreciated. 来自gcc /动态链接专家的答案非常感谢。

For those who are curious, the server in question is Phusion Passenger's logging agent: https://github.com/FooBarWidget/passenger/blob/master/ext/common/LoggingAgent/Main.cpp 对于那些好奇的人,有问题的服务器是Phusion Passenger的日志记录代理: https//github.com/FooBarWidget/passenger/blob/master/ext/common/LoggingAgent/Main.cpp

The C runtime allocates more memory than your process actually uses as part of normal operation. C运行时分配的内存多于您的进程实际用作正常操作的一部分。 This is because allocating memory at the kernel level is extremely slow, and can only be done in page sized blocks (Page size is typically 4kb on x86 boxes, but it can be larger, and is usually 8kb or more on x64 machines). 这是因为在内核级别分配内存非常慢,并且只能在页面大小的块中完成(x86盒子上的页面大小通常为4kb,但它可能更大,在x64机器上通常为8kb或更多)。

Furthermore, when the C runtime receives an allocation request it cannot satisfy, it will often allocate more than is necessary, again, to remove the expense of going to the kernel most of the time. 此外,当C运行时接收到它不能满足的分配请求时,它通常会分配超过必要的次数,以消除大部分时间进入内核的费用。

Finally, if you're using boost goodies, they probably depend on some STL components, such as std::vector . 最后,如果你正在使用boost goodies,它们可能依赖于某些STL组件,例如std::vector These components allocate space for elements using std::allocator<T> , which in some instances will again allocate more space than is actually used. 这些组件使用std::allocator<T>为元素分配空间,在某些情况下,它将再次分配比实际使用的空间更多的空间。 (In particular, node-based structures like std::map , std::set , and std::list usually do this to put the nodes of the list or tree together on the same memory page) (特别是,基于节点的结构,如std::mapstd::setstd::list通常这样做是为了将列表或树的节点放在同一个内存页面上)

Long story short: Don't worry about this. 长话短说:别担心。 Half a meg of memory isn't a lot by any stretch of the imagination (At least nowadays), and most of that is probably just amortizing the use of dynamic allocation functions. 任何想象力(至少现在)都不会占用半兆内存,而且大部分内存可能只是在分摊动态分配功能的使用。 Write up your actual server, and if it's using too much memory, THEN look at ways of reducing memory usage. 写下您的实际服务器,如果它使用了太多内存,那么请查看减少内存使用的方法。

EDIT: If the component of boost you're using happens to be asio, and you're using sockets, you should also know there's some memory consumed in order to maintain buffers for sockets too. 编辑:如果你正在使用的boost组件碰巧是asio,并且你正在使用套接字,你也应该知道为了维护套接字缓冲区而消耗了一些内存。

One way to reduce the memory consumption is to reduce thread stack size. 减少内存消耗的一种方法是减少线程堆栈大小。

Regarding boost , as Steve Jessop commented, you have to be a bit more specific than "boost". 关于提升 ,正如Steve Jessop评论的那样,你必须比“提升”更具体。

Sounds like you have a problem with a base address conflict on some of your dynamic load libraries. 听起来你的某些动态加载库存在基地址冲突问题。 If they require relocation during load, they will be mapped in as private fixed-up copies. 如果它们在加载期间需要重定位,则它们将作为私有固定副本映射。

Re-run prelink across your entire system. 重新运行prelink在您的整个系统。 If the library loads at its preferred address, it will be mapped as shared memory and only cost one copy of the code no matter how many processes are using it. 如果库加载到其首选地址,它将被映射为共享内存,并且只需要代码的一个副本,无论有多少进程使用它。

BTW, prelink was also the fix for KDE. BTW, prelink也是KDE的修复。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM