I use C alot, will defend many of its finer qualities, and have little problem with manual memory management, per se, including using techniques like bump allocators and arenas. (I'm very peculiar about APIs, though. For example, I have my own GNU obstack-like library, but designed to permit building strings byte-by-byte.)

That said, to my mind "large program" and "manual memory management" do not go together. It's difficult to comprehensively reason about large programs in toto in any language. In some respects C is better than many other languages in this regard as there are only a few ways components can reasonably fit together--not many features and complex semantics to cut through. However, when it comes to manual memory management in C it's effectively impossible to reason about the program as a whole, even if all other traps, like aliasing, are taken out of the picture.

So even if I have a large application written entirely in C, it's never built that way, and that's not how I will conceive of it. It's built of discrete components with very minimal--preferably zero in most cases--cross dependencies. In fact, each component is typically maintained as either a single source file or an entirely separate library so that from soup-to-nuts the boundaries (functional and technical) are consistent. Components themselves, even single-file components, will typically be structured similarly internally. I try to avoid utility libraries with ad hoc functionality or even narrow, cross-cutting functionality. And I emphasize strictly functional interface boundaries. So, for example, if I use a bump allocator in a functional component, this fact is completely opaque and irrelevant outside the component. All of this sometimes results in more code duplication than people might normally be comfortable with. But it makes it far easier to reason about each component in isolation, and then in turn reason about their interactions.

A language like Rust is literally built around this type of code flow and data discipline. So in many respects I'm making a strong argument for using Rust instead of C. If you stopped reading here, no problem. But I would still point out that this type of architectural discipline has many other benefits, like making it easier to mix-and-match languages (e.g. C + Lua + Swift) or to do major refactors. Some of the rich semantics of Rust and its ecosystem can easily lead one stray. To my way of thinking, something like Cargo is almost all liability for projects that expect any longevity. And while I think generational memory arenas are awesome, if and when the semantics of the arena leak beyond a functional interface boundary (whether "internal" or "external"--rarely a substantive distinction to me), then that presents a major problem.

IOW, there shouldn't be "large programs" in any language. There should just be a bunch of small programs revolving around a central, cohesive problem model. (A high-level functional problem, not a technical problem like memory management.) And that should hold even if your final artifact is an enormous, static binary. One of the major benefits is that you're not stuck choosing just one memory management technique or even one language. One component can employ a bump allocator in a streaming parser, and another written in a language with mark & sweep GC. And if you enforce strict functional and semantic boundaries so these choices can't leak, you can often mix-and-match them with relative ease. One implication is that sometimes it could be more prudent to write a particular component in C rather than Rust, such as if the Rust component would end up a giant ball of unsafe{} blocks.

This perspective is rather peculiar and unpopular these days, however. When baseline assumptions are an autocompleting IDE and seamless importation of all other software in an ecosystem, the calculus is entirely foreign. So I wouldn't expect it to resonate with many people.