TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

The Horror in the Standard Library

830 点作者 aw1621107大约 8 年前

34 条评论

bluejekyll大约 8 年前
OMG, as I was reading this I thought, &quot;man, this reminds me of a bug I ran into with std::string back in 2000&quot;, A few sentences later, and this is also about std::string and the STL.<p>Mine was different though, after tracking down a memory leak that was happening with the creation of just new empty string, I discovered in the stdlib that there was a shared pointer to the empty string with a reference count of how many locations were using it (ironic that this was intended to save allocations). It turned out this was on Intel and we had what was rare at the time, a multi-processor system. It turned out that the std::string empty string reference count was just doing a vanilla ++, no locking, nothing, variable not marked volatile, nothing.<p>A few emails with a guy in Australia, a little inline assembly to call a new atomic increment on the counter, and the bug was fixed. That took two weeks to track down, mostly because it didn&#x27;t even cross my mind that it wasn&#x27;t in my code.<p>From that point on, I realized you can&#x27;t trust libraries blindly, even one of the most used and broadly adopted ones out there.
评论 #14279124 未加载
评论 #14286184 未加载
评论 #14280097 未加载
faragon大约 8 年前
The problem is forgetting that dynamic memory usage is not &quot;free&quot; (as in &quot;gratis&quot; or &quot;cheap&quot;). In fact, using std::string for long-lived server processes doing intensive string processing (e.g. parsing, text processing, etc.) is already known to be suicidal since forever, because of memory fragmentation.<p>For high load backend processing data, you need at least a soft real-time approach: avoid dynamic memory usage at runtime (use dynamic memory just at process start-up or reconfig, and rely on stack allocation for small stuff, when possible).<p>I wrote a C library with exactly that purpose [1], in order to work with complex data (strings -UTF8, with many string functions for string processing-, vectors, maps, sets, bit sets) on heap or stack memory, with minimum memory fragmentation and suitable for soft&#x2F;hard real-time requirements.<p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;faragon&#x2F;libsrt" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;faragon&#x2F;libsrt</a>
评论 #14285093 未加载
评论 #14280205 未加载
arunc大约 8 年前
I encountered exactly the same issue few years ago in UIDAI in one of our large scale biometric matchers and the resolution was exactly the same. After a week of debugging I found that the libstdc++ allocator was the culprit. I found [1] and confirmed the same, which helped in fixing this issue.<p>The thing that was more interesting (or sad) was to know that the GCC developers didn&#x27;t expect the multithreaded applications to be long running.<p>&quot;Operating systems will reclaim allocated memory at program termination anyway. &quot;<p>[1] <a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;libstdc++&#x2F;manual&#x2F;mt_allocator_impl.html" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;libstdc++&#x2F;manual&#x2F;mt_allocator...</a>
评论 #14279171 未加载
评论 #14279791 未加载
alyandon大约 8 年前
I myself ran across this same scenario many years ago with a similar amount of hair pulling and eventually concluding that the GNU libstdc++ allocator wasn&#x27;t reusing memory properly. Unfortunately, I was never able to pare down the application to the point that I had a reproducible test case to report upstream.<p>GLIBCPP_FORCE_NEW was the solution for the near term and since I was deploying on Solaris boxes I eventually switched to the Sun Forte C++ compiler.<p>It really bugs me that this problem still exists. :-&#x2F;
评论 #14278485 未加载
bgd11大约 8 年前
All the technicalities aside the writing style of the author is amazing. I would have never thought that someone can create such an intense narrative with &#x27;malloc&#x27; as the main character
评论 #14284495 未加载
firethief大约 8 年前
&gt; Nothing made any sense until we noticed the controller microservice&#x27;s memory consumption. A service that should be using perhaps a few hundred megabytes at most was using gigabytes and growing... and growing... and growing... and growing...<p>Not identifying this until many hours after symptoms were impacting users sounds like a pretty big monitoring blind spot.
评论 #14280178 未加载
cyphar大约 8 年前
Did you report the issue upstream with a patch? The solution to &quot;the standard library is broken&quot; is to fix the standard library, no? It&#x27;s all free software after all.
评论 #14278276 未加载
评论 #14278271 未加载
评论 #14278566 未加载
评论 #14278822 未加载
stephen_g大约 8 年前
Things like this is why I was happy to see the LLVM project write their own C++ standard library. libstdc++ has always seemed a bit hacky and fragile to me. It&#x27;s great to have an option which is a more modern, clean codebase.<p>Have you tested to see if this works better with LLVM libc++?
评论 #14278824 未加载
评论 #14278831 未加载
rurban大约 8 年前
The &quot;make malloc faster&quot; part was done over a decade ago with the followup from ptmalloc2 (the official glibc malloc) to ptmalloc3. But it added one word overhead per region, so the libc people never updated it to v3. perf. regression. They rather broke the workarounds they added. And now they are breaking emacs with their new malloc.
consultSKI大约 8 年前
&gt;&gt; Most operators in C++, including its memory allocation and deletion operators, can be overloaded.<p>Have I mentioned lately how much I hate C++?<p>Great read.
spyder81大约 8 年前
&quot;Then I remembered reading something long ago&quot; is when experienced programmers are worth their weight in gold.
brynet大约 8 年前
Interestingly for recent versions of GCC (&gt;=4.0) GLIBCXX_FORCE_NEW is defined for libstdc++, not GLIBCPP_FORCE_NEW.<p><a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;libstdc++&#x2F;manual&#x2F;mt_allocator_impl.html" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;libstdc++&#x2F;manual&#x2F;mt_allocator...</a>
charles-salvia大约 8 年前
I&#x27;m a bit confused here.<p>&gt;&gt; Most operators in C++, including its memory allocation and deletion operators, can be overloaded. Indeed this one was.<p>Okay, well, firstly - the issue here seems to be a problem with the implementation of std::allocator, rather than anything to do with overloading global operator new or delete. Specifically, it sounds like the blog author is talking about one of the GNU libstdc++ extension allocators, like &quot;mt_allocator&quot;, which uses thread-local power-of-2 memory pools.[1] These extension allocators are basically drop-in extension implementations of plain std::allocator, and should only really effect the allocation behavior for the STL containers that take Allocator template parameters.<p>Essentially, libstdc++ tries to provide some flexibility in terms of setting up an allocation strategy for use with STL containers.[2] Basically, in the actual implementation, std::allocator inherits from allocator_base, (a non-standard GNU base class), which can be configured during compilation of libstdc++ to alias one of the extension allocators (like the &quot;mt_allocator&quot; pool allocator, which does <i>not</i> explicitly release memory to the OS, but rather keeps it in a user-space pool until program exit).<p>However, according to the GNU docs, the <i>default</i> implementation of std::allocator used by libstdc++ is <i>new_allocator</i> [3] - a simple class that the GNU libstdc++ implementation uses to wrap raw calls to global operator new and delete (presumably with no memory pooling.) This allocator is of course often slower than a memory pool, but obviously more predictable in terms of releasing memory back to the OS.<p>Note also that &quot;mt_allocator&quot; will check if the environment variable GLIBCXX_FORCE_NEW (not GLIBCPP_FORCE_NEW as the author mentions) is set, and if it is, bypass the memory pool and directly use raw ::operator new.<p>So, it looks like the blog author somehow was getting mt_allocator (or some other multi-threaded pool allocator) as the implementation used by std::allocator, rather than plain old new_allocator. This could have happened if libstdc++ was compiled with the --enable-libstdcxx-allocator=mt flag.<p>However, apart from explicitly using the mt_allocator as the Allocator parameter with an STL container, or compiling libstdc++ to use it by default, I&#x27;m not sure how the blog author is getting a multi-threaded pool allocator implementation of std::allocator by default.<p>[1] <a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc-4.9.4&#x2F;libstdc++&#x2F;manual&#x2F;manual&#x2F;mt_allocator.html" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc-4.9.4&#x2F;libstdc++&#x2F;manual&#x2F;ma...</a><p>[2] <a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc-4.9.4&#x2F;libstdc++&#x2F;manual&#x2F;manual&#x2F;memory.html#idm140050801737120" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc-4.9.4&#x2F;libstdc++&#x2F;manual&#x2F;ma...</a><p>[3] <a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc-4.9.4&#x2F;libstdc++&#x2F;manual&#x2F;manual&#x2F;memory.html#idm140050801737120" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc-4.9.4&#x2F;libstdc++&#x2F;manual&#x2F;ma...</a>
评论 #14279152 未加载
评论 #14280608 未加载
bboreham大约 8 年前
Post doesn&#x27;t actually say what was broken, or indeed prove the location of broken-ness. Just that it went away with a different compile option.<p>Exciting writing, but lacking a point.
评论 #14279466 未加载
halayli大约 8 年前
this conclusion might be wrong. the code in question while it might not be allocating&#x2F;freeing memory it might be stumbling on memory blocks and corrupting mem management structures. Turning the flag on might be fixing the issue by mere luck because memory allocations, locations and structures would be different
评论 #14278673 未加载
SFJulie大约 8 年前
Memory fragmentation due to dynamic non fixed size data structure and multithreading is an old foe. That may not be fixable in c&#x2F;c++<p>Worker A allocates dynamic stuff. Algo take a segment (0+sof(str)(ofA) + n) Work B Allocates to create same kind of data structure (fragment of a JSON) [ofA, OfB] Wk A resume allocating, boundary of [0, ofA] exceeded, no free contiguous space up or down [Ofb, OfC] allocated Wk C enters wants to alloc, but sizeof(string) make it bigger than [0, OfA] so [ofD, ofE] asked .... and the more concurrent workers the more interleaving of memory allocation go on with fragmented memory.<p>Since malloc are costly the problem known, a complex allocator was created with pools of slab and else, probably having one edge case, very hard to trigger having phD proven really complex heuristic.<p>CPU power increase, more loads more workers, interleaving comes in, edge case gets triggered.<p>And C&#x2F;C++ makes fun of fortran with its fixed size data structures embracing any new arbitrary size arbitrary depth data structure for the convenience of skipping a costly waterfall model before delivering a feature or a change in the data structure and avoiding bike shedding in committees.<p>Human want to work in a way that is more agile than what computers are under the hood.<p>Alternative:<p>Always allocated fixed size memory range for data handling, and make sure it will be enough. When doing REST make sure you have an upper bound, use paging&#x2F;cursors, which require FSM, have all FP programmers say mutable are bads, sysadmin say that FSM are a pain to handle when HA is required, and CFO saying SLA will not be reached and business model is trashed, and REST fans saying that REST is dead when stateful.<p>Well REST is a bad idea.
评论 #14286332 未加载
评论 #14280486 未加载
squidlogic大约 8 年前
Amazing write-up. Informative and gripping in its prose.
评论 #14278877 未加载
评论 #14278588 未加载
TimJYoung大约 8 年前
I&#x27;m not sure if the other debug tools mentioned offer this, but AQTime Pro:<p><a href="https:&#x2F;&#x2F;smartbear.com&#x2F;product&#x2F;aqtime-pro&#x2F;overview&#x2F;" rel="nofollow">https:&#x2F;&#x2F;smartbear.com&#x2F;product&#x2F;aqtime-pro&#x2F;overview&#x2F;</a><p>has an allocation profiler that can be used to track down this sort of problem. You can take allocation snapshots while the application is running to see where the allocations are coming from (provided that you can run AQTime Pro against a binary with debug symbols&#x2F;info).<p>I&#x27;m not affiliated with the company - just a happy customer that has used them for years with Delphi development.
评论 #14284468 未加载
tripzilch大约 8 年前
Upvoted for the Lovecraft and pulp horror lit references, and starting with &quot;It was a dark and stormy night ...&quot; :-)<p>Great writing, great read.
jcalvinowens大约 8 年前
I don&#x27;t understand the point of this article... if you think there&#x27;s a bug in the library, fix it. Don&#x27;t write a melodramatic blog post lamenting how horrible it is in the hope somebody else will do it for you.<p>This isn&#x27;t particle physics, it&#x27;s code: we don&#x27;t have to guess, we can look at it and see how it works.
bogomipz大约 8 年前
This was a nice write up, however I didn&#x27;t follow how memory fragmentation was related to a memory leak. Can someone explain? I understand that alternate memory allocators would help with the fragmentation issue but how does the choice of allocators affect memory leakage?
评论 #14281882 未加载
grandinj大约 8 年前
I&#x27;m guessing the cpp thing is a holdover from the days when the glibc maintainer was less than entirely helpful. There has been actual improvements in glibc in this area lately so hopefully these kinds of hacks will slowly go away.
评论 #14291505 未加载
odbol_大约 8 年前
Is C++ now going the way of PHP, where to have an actual working program you have to disable all the defaults in some mysterious but crucial ritual?
dummy323大约 8 年前
<a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;bugzilla&#x2F;show_bug.cgi?id=80658" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;bugzilla&#x2F;show_bug.cgi?id=80658</a>
selimthegrim大约 8 年前
James Mickens, move over. There&#x27;s a new sheriff in town.
jonnycomputer大约 8 年前
the idea that we should always blame ourselves first has merit. but frankly some bugs, just p e r s i s ttt.<p>like this one, with fputcsv in PHP. <a href="https:&#x2F;&#x2F;bugs.php.net&#x2F;bug.php?id=43225" rel="nofollow">https:&#x2F;&#x2F;bugs.php.net&#x2F;bug.php?id=43225</a>
Safety1stClyde大约 8 年前
It was only yesterday that I was reading another discussion from hacker news about problems with Gnu C library.<p><a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14271305" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14271305</a>
评论 #14291506 未加载
logicallee大约 8 年前
People forget that C++ is just a <i>tool</i>, like a screwdriver or a hammer. A good carpenter knows when it&#x27;s time to take a metallurgy class and resmelt his hammer, because its composition is not correct for being a hammer.
评论 #14278487 未加载
评论 #14278484 未加载
Ono-Sendai大约 8 年前
So where&#x27;s the bug report with repro test code?
评论 #14280863 未加载
Pica_soO大约 8 年前
One thing, not even mentioned in the article is the component-scouting &amp; profiling-phase, which completely failed. You do not go all in with a project on a crucial library, that you did not profile with the real workload.<p>One small prototype, never run under full load, with mock up classes- not even the size of future classes, mock up operations(not even close to the real workload) and sometimes not even the final db-type attached. Yeah, hard to see the future, but why not drive the test-setup to the limits and go from their?<p>Instead the whole frankenservice is run once for ten minutes and declared by all involved worthy to bare the load of the project.<p>Here is to lousy component scouting and then blaming it on the architect.
tbodt大约 8 年前
Maybe it&#x27;ll get fixed now that a post saying &quot;libc++ is broken&quot; got hackernewsed
评论 #14278480 未加载
ris大约 8 年前
The correct response is to file a bug report, not write a clickbait-y article.
mtanski大约 8 年前
Yeah malloc() is pretty terrible in glibc by modern standards. For some workloads it just can&#x27;t keep up and ends up fragmenting space in such a way that memory can&#x27;t be returned to the OS (and thus be used for the page cache) and you end up in this performance spiral.<p>I always deploy C++ server on jemalloc. Been doing it for years and while there&#x27;s been occasional hicks up when updating it has provided much more predictable performance.
评论 #14278535 未加载
评论 #14278530 未加载
nly大约 8 年前
Actually it is C&#x27;s malloc and free that is &quot;broken&quot;. malloc() takes a size parameter, but free() doesn&#x27;t. This imbalance means it can never be maximally efficient. Whatever GNU stdlibc++ is doing is probably, on balance, a net win for most programs.<p>It&#x27;s not exactly roses in C++ either of course. You can do better than the standard library facilities. Andrei Alexandrescu gave a great, entertaining, and technically elegant talk on memory allocation in C and C++ at Cppcon 2015 that is well worth watching<p><a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=LIb3L4vKZ7U" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=LIb3L4vKZ7U</a>
评论 #14279173 未加载
评论 #14278430 未加载
评论 #14279552 未加载
评论 #14278639 未加载
评论 #14282920 未加载
评论 #14278571 未加载