If you’re not GCing, you will almost certainly run into OOMs.
I’m not aware of an FaaS that would hide the OOM… that falls under the “not a real thing” category I mentioned previously. It would just be a failed request, which is a very visible effect.
Would you like to link me to the Lamda docs that say it will automatically retry the request in case of an OOM?
Also consider that code which OOMs will do so unpredictably. It may have completed half of a task, leaving that task in a corrupt state that requires manual intervention from a human to recover from. If everyone wrote fully idempotent code that can somehow skip the already-completed updates and continue where the OOM occurred, this wouldn’t be a problem, but that isn’t what everyone does. This is certainly a large reason why FaaS do not retry requests automatically at all, in most cases.
> If the service is configured to automatically kill and restart instances after some time or some number of requests, it seems like a reasonable tradeoff.
I don’t believe Lambda has any configuration parameters for those things. That’s not how this is meant to work. Lambda will kill the instance when it has been idle for too long, and that’s the primary factor.
You could manually exit the process when your conditions are met, but why? The benefits of turning off the GC are likely to be negligible. This is a lot of complexity for no real gain. It would take some seriously huge gains demonstrated by well-written benchmarks to convince me that any of this is worthwhile for a FaaS function.
Grug would rather fight t-rex.[0]
If you need absolute performance and control over garbage collection, it’s better to just write the lambda in Rust than to try to hack together a solution by turning off the GC and hoping it doesn’t blow up at the wrong moment.
From that link, here are two choice quotes that I think are highly relevant:
> When you invoke a function, two types of error can occur. Invocation errors occur when the invocation request is rejected before your function receives it. Function errors occur when your function's code or runtime returns an error.
> […]
> When you invoke a function directly, you determine the strategy for handling errors related to your function code. Lambda does not automatically retry these types of errors on your behalf. To retry, you can manually re-invoke your function, send the failed event to a queue for debugging, or ignore the error. Your function's code might have run completely, partially, or not at all. If you retry, ensure that your function's code can handle the same event multiple times without causing duplicate transactions or other unwanted side effects.
So, it won’t automatically retry if a function is being directly invoked and OOMs, which I believe was the context of my most recent reply.
There are a few limited scenarios where certain AWS services that are invoking a Lambda asynchronously will decide to retry a couple of times, because it assumes that this type of function will be okay to call multiple times with the same input. Definitely not something worth relying on.
https://devblogs.microsoft.com/oldnewthing/20180228-00/?p=98...
[1]: https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Dev...
> […] Similarly, function pointers should be used only if there is a very strong justification for doing so because they can seriously restrict the types of automated checks that code checkers can perform. For example, if function pointers are used, it can become impossible for a tool to prove the absence of recursion, requiring alternate guarantees to make up for this loss in checking power.
In other words, static analysis beats code cleanliness, in this perspective.
My favorite is a missile. Evidently the program leaks memory like crazy. Solution was to determine how much memory would be required for the platform to fly to its farthest possible target + some margin.
Alternatively are stock trading platforms written in Java. Disable the GC entirely because trading hours are only a a limited portion of the day. Restart the program daily.
This might be apocryphal, as software for this class of embedded system almost certainly doesn't dynamically allocate anything; probably doesn't even use pools.
I have a friend who works on missile software at a big defense contractor, and they do actually clean up their memory.
> This sparked an interesting memory for me. I was once working with a customer who was producing on-board software for a missile. In my analysis of the code, I pointed out that they had a number of problems with storage leaks. Imagine my surprise when the customers chief software engineer said "Of course it leaks". He went on to point out that they had calculated the amount of memory the application would leak in the total possible flight time for the missile and then doubled that number. They added this much additional memory to the hardware to "support" the leaks. Since the missile will explode when it hits its target or at the end of its flight, the ultimate in garbage collection is performed without programmer intervention.
[0] https://devblogs.microsoft.com/oldnewthing/20180228-00/?p=98...
So, as long as you write Go in malloc-less C-style (which, admittedly, is a non-insignificant restriction), your program will be able to run just fine forever.
What happens if you write your Go functions in this malloc-less C style and they have to grow their stack? Doesn't this mean the old stack is now leaked memory?
But I don't know enough about Go internals to be 100% sure.
Relatedly, unlike languages like Java, Go doesn't have a moving GC--once something is allocated on the heap, the address is fixed.
I'm not sure how realistic it is to code in an entirely malloc-less style in Go, though, given the limited ability to pass references to stack-allocated objects.
Note that the decision to force heap allocation is done at compile time, partly because of the semantics of goroutine stack reallocation as the previous poster hinted at. In principle Go could conditionally copy to heap at runtime, but that's just not Go's style of engineering--that's more in the vein of the JVM and similar environments which push more complexity into the runtime rather than compile time. Though maybe it will or has already begun to go down that road.
> Wouldn't you have to avoid memory leaks?
I've not played with it, but I'd expect that every heap allocation would essentially be a memory leak in that mode
Note that GC can be triggered manually.
I've had to do that using the wasm target so that I'd only trigger go GC cycles when the browser was idle. Eventually that use-case might disappear as the integration with a garbage-collected wasm gets deeper.
1. You know you’re definitely not allocating on the heap;
2. Your workload is bursty and you can simply keep everything until the process dies and memory is released.
However, you might not care (app running too short), or you might turn it off only temporarily (say time-critical section you don't want to be interrupted by GC).