Live data from Hacker News

Std::string half of all allocations in the Chrome browser process

groups.google.com

111–120 of 170 posts

Re: Std::string half of all allocations in the Chrome browser process

#111
post #23

Earlier quoted context omitted.

> Lessons learned, their strings work It is worse than that, because the other alternative systems programming languages that eventually lost to C and C++ also had their string type. Just C did not, and C++ followed along due to its compatibility story.

And here is where C shines compared to C++: At least in C you know that strings are garbage, and you never pretend for a second that everything will be fine. C++ will claim "oh ho ho, we have a string type, don't worry!" and then people will get burned.

If you read the discussion, you would that people are getting burned by converting all the time between char* and std::string, because Google isn't using the same string types across all APIs.

I rather have secure strings, even if every now and then they require some attention to.

Re: Std::string half of all allocations in the Chrome browser process

#112

Earlier quoted context omitted.

It boggles the mind how many different ways to represent Strings there are in C++, and String handling in general is the major reason I'll never touch it (or C) with a 10 feet pole. I'm interested to hear though how the String handling in Java is broken. This is everything I have to know: - String - CharSequence - char[] / Character[] - StringBuilder Done. Finito. Strings are immutable, the GC will clean up after me.…

Except that: - In CJK languages, unicode codepoints can't be represented in 2 bytes. They take up 2 'char' objects; the first is a surrogate code point. - In the presence of surrogates, charAt() and length() give wrong answers. Their indexes refer to the number of 'char' objects up through that point, not the number of Unicode codepoints. If there is a surrogate codepoint present anywhere before your index in the str…

I was aware of the substring issue and the fact that CJK languages require 2 chars, but I might have used codePointAt() instead of offsetByCodePoint(), to be honest. So I agree unicode string indexing is not as easy as it should be, due to a stupid API - but if thats all, I'm not sure that passes for 'hard'. It is also not something inherent to strings in general, the language designers simply messed this up.

Btw., I think they fixed the memory leak in recent VMs by removing that optimization.

Re: Std::string half of all allocations in the Chrome browser process

#113
post #3

Earlier quoted context omitted.

The C++ string library cannot bind the string to the stack frame since it doesn't know how long it's going to live. I suppose the compiler might realize that however and replace dynamic allocation by a static one but I'm not sure it's allowed to do that.

> The C++ string library cannot bind the string to the stack frame since it doesn't know how long it's going to live. Huh? If course it could, unless I'm not understanding you correctly. A class like: class smallstr { char stack_str[128]; char* heap_ptr; } can easily (with enough logic in the public methods) store small strings in `stack_str` and once it grows larger, allocate some space on the heap, make `heap_ptr`…

Well, you have to take the context of our discussion in consideration, I meant that you couldn't dynamically elect to allocate your buffer on the stack instead of the heap at runtime in the constructor. Your solution just allocates a 128B buffer on the stack for all strings which may or may not end up being used.

That makes your string object 128B larger in all situations. Since we were talking about std::string, I'm pretty sure many people wouldn't be happy if sizeof(std::string) suddenly took 128B (g++'s sizeof(std::string) is 8B on my system).

What I had in mind was stuff like alloca and other local scope allocation techniques that would get tied to the constructor stack frame not the caller's.

Re: Std::string half of all allocations in the Chrome browser process

#114

Earlier quoted context omitted.

Except that: - In CJK languages, unicode codepoints can't be represented in 2 bytes. They take up 2 'char' objects; the first is a surrogate code point. - In the presence of surrogates, charAt() and length() give wrong answers. Their indexes refer to the number of 'char' objects up through that point, not the number of Unicode codepoints. If there is a surrogate codepoint present anywhere before your index in the str…

I was aware of the substring issue and the fact that CJK languages require 2 chars, but I might have used codePointAt() instead of offsetByCodePoint(), to be honest. So I agree unicode string indexing is not as easy as it should be, due to a stupid API - but if thats all, I'm not sure that passes for 'hard'. It is also not something inherent to strings in general, the language designers simply messed this up. Btw., I…

The point is that these are trade-offs. The reason for the stupid API is because by getting precise multilingual handling, you give up either O(1) string indexing or representing characters in less than 3 bytes/char. If you naively use offsetByCodePoint on megabyte-long strings, you may find your performance slows to a crawl.

The reason for the memory leak is that you can either have fast substring() or accidental memory leaks when substrings are stored in persistent data structures. Not both. If they removed the optimization, then suddenly str.substring(1) takes O(1) time and on a megabyte string allocates a full copy of the entire megabyte. In some other use-case, the full copy is far worse.

There are others, too. Idiomatic Java uses '+' for string concatenation, but this is O(n^2) time when done repeatedly. (Except that HotSpot optimizes out the repeated allocations when all concatenations appear in the source code, but it still can't do anything about loops.) To get around this performance pitfall, there is StringBuilder. Now Java programmers need to know 2 APIs. Well, more like 6, considering there's also CharSequence, ByteBuffer, StringBuffer, and char[].

C++ has always had the philosophy of "The programmer knows their requirements better than we do". This is why it is complex; because problems are complex, and it is designed to solve many problems. It's very rare for a language designer of a popular language to actually be stupid; it's very common for a language to get used outside of the domains that the language designer optimized for.

Re: Std::string half of all allocations in the Chrome browser process

#115
post #70
post #66

Earlier quoted context omitted.

So which web browsers are not written in C++?

Almost all of Windows (including apps that predominantly do string and tree manipulation) is written in C++. Almost all of Linux userspace is written in C. These are still terrible, insecure, fragile languages which cause frustration and loss to programmers and users every day.

Shame you're downvoted, because you're pretty much right. Don't get me wrong, correct code can very well be written in C/C++. It's just 95% of the programmers using those languages are not very skilled. The programs tend to be wrong and fragile. In C++, most of this fragility derives from its C-roots.

C/C++ is also a poor match to today's CPUs. It's very slow compared to what the hardware is capable of. Compare for example with Intel ispc (https://ispc.github.io/). It gives some idea how much performance we're currently missing.

When C was young, memory latency was typically 1 or 2 clock cycles. There was no pipelining, at most a simple state machine that would finish in a few clock cycles. A branch didn't cost much. A few cycles at most. Neither did a pointer reference. Random access was almost as fast as sequential access.

Today's CPUs have memory latency of 150-300 clock cycles. A modern CPU core can typically retire 1-4 instructions per clock cycle. A single instruction takes typically about 16 clock cycles from decoding until retire. So CPUs have to often execute blind and just guess where the execution flow will go. Branches modify this flow. CPUs simply guess the flow, branch predict. When they're wrong, they just have to invalidate currently executing instructions and start again. Branches are something to avoid. Especially unpredictable ones. Function pointers are branches. Even though they can be predicted, they often just fall out of the branch predictor cache.

We need something that can minimize the costs modern CPUs are bad at. C/C++ is very branchy and uses slow function pointers often (vtable, switch jump tables, etc).

The problem is, there's more variation among CPUs than ever before, even within same instruction set architecture. For x86, not only the costs for instructions are wildly different, but the instruction set support is fragmented.

C/C++ is not the last word. Unsafe and way too slow compared to what current hardware is capable of. The problem is, the language that is safer and a good match just does not exist yet. Some safety can be sacrificed for greater speed, but it should be situational choice by the programmer, not the only way or even default.

C/C++ is what I do at my day job.

Re: Std::string half of all allocations in the Chrome browser process

#116

The problem with std::string is that it's named wrong. It should be called std::string_buffer, because that is what it is. Its performance characteristics are closer to a std::vector than a std::array (now available since C++11). Many projects cannot copy around std::vector in good conscience. They really want a copy-on-write string, an immutable string, a rope, a reference-counted string, or an always-in-place strin…

std::string_view didn't make it into C++14.

Re: Std::string half of all allocations in the Chrome browser process

#117

Earlier quoted context omitted.

I was aware of the substring issue and the fact that CJK languages require 2 chars, but I might have used codePointAt() instead of offsetByCodePoint(), to be honest. So I agree unicode string indexing is not as easy as it should be, due to a stupid API - but if thats all, I'm not sure that passes for 'hard'. It is also not something inherent to strings in general, the language designers simply messed this up. Btw., I…

The point is that these are trade-offs. The reason for the stupid API is because by getting precise multilingual handling, you give up either O(1) string indexing or representing characters in less than 3 bytes/char. If you naively use offsetByCodePoint on megabyte-long strings, you may find your performance slows to a crawl. The reason for the memory leak is that you can either have fast substring() or accidental me…

You made some good points, but I'm not sure all of these are necessary trade offs.

Lets say that the issue of code points not fitting into 16 bit chars requires a separate indexOf() API, to preserve O(1). They could have solved this one with better method naming, or at least improved documentation, so people are aware of the fact. The String#charAt() Javadoc is not really useful, unless you fully understand the implications of: "If the char value specified by the index is a surrogate, the surrogate value is returned." Also, if you are handling CJK strings, is there actually a need to split them by charAt()? The runtime could just tag such strings and use the fastest indexing method, falling back to the slow one for those.

Concatenation: true, and that the jit can't optimize most loops by using StringBuilder is a little embarrassing. Abstractions are always leaky, but this one I think could be improved, so that more cases would be made faster by the runtime.

Of course language designers aren't usually stupid, but its not like they all were created in some cozy Languages Workshop, where they could take their time to ripen, being guarded over by benevolent gardeners. See PHP, see Javascript, and of course Java, too. We don't have to accept accidental complexity as a given, there are useful abstractions, and we should use them. Rust and C# are better than previous attempts, imho, because they got proper funding and are designed by people who know what they're doing. And the whole field of software is better for it!

If you are Google, you are in the unique position of having top talent and huge amounts of servers. In that case, the trade-off to use C++ is probably the right one. People can handle its complexity, and it pays off due to increased performance, because the code runs on a million servers. But this simply isn't true for 99% of the business, and using C or C++ is not the optimal choice for them.

Re: Std::string half of all allocations in the Chrome browser process

#118

The problem with std::string is that it's named wrong. It should be called std::string_buffer, because that is what it is. Its performance characteristics are closer to a std::vector than a std::array (now available since C++11). Many projects cannot copy around std::vector in good conscience. They really want a copy-on-write string, an immutable string, a rope, a reference-counted string, or an always-in-place strin…

std::string_view didn't make it into C++14.

Ah, I guess I'm behind in the news then. I thought it was in an experimental header. I guess I hope it's in C++17 then, or else we may need to root for a good ranges proposal that covers the same ground.

Re: Std::string half of all allocations in the Chrome browser process

#119
post #70

Earlier quoted context omitted.

Almost all of Windows (including apps that predominantly do string and tree manipulation) is written in C++. Almost all of Linux userspace is written in C. These are still terrible, insecure, fragile languages which cause frustration and loss to programmers and users every day.

Shame you're downvoted, because you're pretty much right. Don't get me wrong, correct code can very well be written in C/C++. It's just 95% of the programmers using those languages are not very skilled. The programs tend to be wrong and fragile. In C++, most of this fragility derives from its C-roots. C/C++ is also a poor match to today's CPUs. It's very slow compared to what the hardware is capable of. Compare for e…

>> It's just 95% of the programmers using those languages are not very skilled.

High level languages just make it easier for crappy programmers to approximate a working solution.

Re: Std::string half of all allocations in the Chrome browser process

#120
post #4

I've worked on a project that used all of these: std::string, QString, OString, char*. All were required by a different library that we needed. This is why a good string type should be in core language.

This is the problem with C++ (and in a certain part, with C) "Everybody" has their own C++ string (MFC, QT, several libraries, heck, even GObject library has their strings) Same with C Now, you won't see anybody reimplementing strings in Java. C#, Python, JS, etc Lessons learned, their strings work std:string is certainly a step forward and should be used for most projects today

So in C# (on the .NET VM) when you allocate a string that's more than 65K when does it get freed?

I wouldn't call that 'working'.

Post reply on HN