You can use a per-request memory arena built with a simple bump allocator and then free the entire block when the request has been handled.
* if what you're vending is the software instead of the service (not what people usually do now, but there was a time), then this approach does provide for some obfuscation of IP and various secrets.
* for some demand/resource profiles, CPU & memory issues are a lot easier to run into. The one I experienced with this project was targeting a serious e-commerce product to the context of 20-30 year old shared hosting environments (again, not what people would do now), but there may be different situational niches today.
* familiarity. Sometimes you use what you know. And in the late 90s today's most popular web languages were still years away from being the convenient platform they'd become. The other popular options were Perl, maybe Java, possibly ColdFusion/VB/PHP.
That said, you're correct: memory management was a pain, and by 2005 or so it was pretty clear that programmer cycles were as or more valuable than CPU and respectable frameworks were starting to coalesce in languages much better suited for string manipulation, so the ROI was not great. And of course, today you have other systems languages available like Go and Rust...
Regarding just spending more money on memory - I agree that it’s definitely cheaper but it’s not only about wasting bytes of memory. If the garbage collector has a lot of work to do it may also impact response time/throughput.
And yes, C# did a pretty good job with implementing mechanisms for reducing allocations on a language level. This definitely helps to reduce garbage collection.
That being said, it's still possible to reverse engineer the code; it just makes it harder.
Serving web traffic simply isn't a very memory hungry task.
I dunno about this assertion. Maybe it seems like the bottleneck is rarely CPU/memory when you're throwing 1GB RAM + dedicated instance at a webapp, but, for example Jenkins absolutely trashes any 1GB RAM instance because it runs out of RAM and/or CPU.
My homegrown builder/runner CI/CD system, running the same `go build/test` commands, the same `git checkout` commands etc, written in C, peaks at a mere 60MB of RAM usage.
I feel we are collectively underestimating just how much extra RAM is needed the popular languages that run a typical GC.
[EDIT: I no longer even use my simple C app - I find a `make` cronjob for every 2m uses even less RAM, because there is no web interface anymore, I ssh into that machine to add new projects to the makefile]
If anything, you've gone further along the "also (at least sort of) practical" scale than I expected.
Given as mentioned elsewhere a per-request arena + bump allocator system, it might actually be -genuinely- practical (to the extent that writing application logic in C is at all ;)
Bravo.
This isn't something that I would use for an embedded application. The fact that it allows uploading a compiled binary implies that it's for developing a web application in C, as opposed to merely adding a web endpoint to an embedded application.