Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Remove conditional allowing spawn instead of fork and default to fork. Remove various code supporting fork. Background on WHY: Fork, while creating processes much faster for us, relies on programs being copy-on-write(CoW) friendly to take advantage of shared memory. To do this, your program needs to preload as much of it's code ahead of time and avoid writing to memory locations on OS pages containing objects shared with other processes. Ruby's garbage collector is naive in how it allocates objects on the ruby heap pages as both old and new objects can be located on the same OS page. Because most objects die young, it's wise to keep old objects on separate OS pages from new objects. If a parent or child process allocates or frees memory on the OS page containing shared memory objects, the whole OS page is copied, including the shared objects. This happens frequently if your heap is fragmented with old and new objects. In addition, ruby, as of 2.2, has the notion of young and old objects and the garbage collector can be more efficient by only traversing young objects on a minor GC since young objects generally die young. Unfortunately, the age field is used to track this and is directly on the object header. This means that after surviving 3 GCs, an object is 'touched' to mark it's age as 'old'. This causes any shared memory on the same OS page to be copied with this object. This was mitigated by https://github.com/ko1/nakayoshi_fork, but only for objects created before you fork. Any new objects created after fork could be allocated on an OS page coresident with shared objects, causing the whole OS page to be copied. Ultimately, the shared memory for ManageIQ processes was often less than 15% within minutes of the processes starting and this number continued to drop as more and more shared memory locations were copied on a "neighboring" write. This means that fork was only buying us faster process creation. As we move towards running ManageIQ in containers, we also need to move towards running processes in isolation via command lines. We have begun separating out dependencies and selectively loading them via bundler groups, which drops memory usage for non-fork processes but makes fork less efficient since less and less code is preloaded and shared. Finally, fork is not implemented in every platform, such as Windows, or even ruby, jRuby for example, so it was preventing usage of ManageIQ in those ecosystems. With all this said, it's time to say goodbye to fork.
- Loading branch information