Modern JavaScript engines primarily use the mark-and-sweep algorithm: 1) The algorithm starts from root objects (global variables, currently executing functions) and marks all reachable objects, 2) After marking, it sweeps through memory and reclaims any unmarked objects, 3) This approach correctly handles circular references that reference counting cannot, 4) Most modern engines combine mark-and-sweep with other techniques like generational collection, 5) V8 (Chrome, Node.js), SpiderMonkey (Firefox), and JavaScriptCore (Safari) all use variations of mark-and-sweep, 6) The basic algorithm has been enhanced with incremental and concurrent approaches to reduce performance impact, 7) Mark-and-sweep operates periodically rather than when reference counts change, 8) This algorithm allows the engine to reclaim memory even in complex object reference graphs.