i have a suspicion. First - are you able to open support tickets with Microsoft?
Easiest way to check my suspicion is capture [\SQLServer:Memory Node(*)\Stolen Node Memory (KB)] for both NUMA nodes, and compare the sum to [\SQLServer:Memory Manager\Stolen Server Memory (KB)]. If my suspicion is correct, when trouble is brewing the discrepancy between the two - which seem like they should always agree - will be quite high. The other tell-tale characteristic: up to N-1 SQLOS NUMA nodes may have show this relationship (where N is the count of NUMA nodes)
[database node memory] + [stolen node memory] + [free node memory] > [total node memory]
i describe the problem somewhat in these blog posts.
https://sql-sasquatch.blogspot.com/2018/07/sql-server-2016-memory-accounting.html
https://sql-sasquatch.blogspot.com/2018/10/sql-server-2016-memory-accounting-part.html
The basic accounting problem is that sometimes buffer pool growth occurs in a way that buffer descriptor blocks get allocated from SQLOS node A but the pages referenced in the bdbs actually come from SQLOS node B. The result of this condition is that a portion of physical memory controlled by SQLOS gets double-counted: the same memory is accounted on node A (where the bdbs live) as [Database Node Memory] AND accounted on SQLOS node B as [Stolen Node Memory]. That situation is confusing and inefficient... but its not the full bloom of the problem yet.
The problem fully blooms when so much Node B [stolen node memory] is also Node A [database node memory] that Node B [database node memory] drops to ~2% of Node B [target node memory]. When that happens, the rate of [\SQLServer:Buffer Manager\Free list stalls/sec] skyrockets - we saw 2000/sec when this happened to us. SQL Server is trying to correct the issue (too little [database node memory]) on Node B by trimming various types of cache on Node B. But it can't!! Because the [stolen node memory] isn't in any of the various expected cache types.
Temporary resolution: when [total node memory] approaches [target node memory] but [database node memory] approaches 2% of [target node memory], execute DBCC DROPCLEANBUFFERS.
kb4536005 resolves this issue in SQL Server 2017 CU20 and SQL Server 2019 CU2.
https://support.microsoft.com/en-us/help/4536005/improvement-fix-incorrect-memory-page-accounting-that-causes-out-of-me
There is a similar sounding fix in SQL Server 2016 SP2 CU5, kb4470916.
https://support.microsoft.com/en-ca/help/4470916/fix-out-of-memory-error-occurs-when-database-node-memory-kb-drops-belo
However, I don't believe kb4470916 resolves the issue with double-accounting. So while it may improve SQL Server response to a single SQLOS node having [database node memory] at the ~2% threshold, i think it leaves open the possibility of poking the bear due to this double-counting. And that may be the situation you are in.
However, if the sum of [stolen node memory] across the two nodes always aligns with [stolen server memory] in the instance, you can forget all about this as if it were a bad dream. :-)