New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement discarding Document objects to reclaim space. #14312
Changes from 1 commit
78c87ea
67bf230
ef50a64
1a201fc
c14c431
File filter...
Jump to…
Implement discarding Document objects to reclaim space.
- Loading branch information
| @@ -68,6 +68,9 @@ pub struct Opts { | ||
|
|
||
| pub output_file: Option<String>, | ||
|
|
||
| /// How much session history to keep in each tab. | ||
| pub max_session_history: usize, | ||
|
|
||
| /// Replace unpaires surrogates in DOM strings with U+FFFD. | ||
| /// See https://github.com/servo/servo/issues/6564 | ||
| pub replace_surrogates: bool, | ||
| @@ -518,6 +521,7 @@ pub fn default_opts() -> Opts { | ||
| userscripts: None, | ||
| user_stylesheets: Vec::new(), | ||
| output_file: None, | ||
| max_session_history: 256, | ||
asajeffrey
Author
Member
|
||
| replace_surrogates: false, | ||
| gc_profile: false, | ||
| load_webfonts_synchronously: false, | ||
| @@ -611,6 +615,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { | ||
| "Probability of randomly closing a pipeline (for testing constellation hardening).", | ||
| "0.0"); | ||
| opts.optopt("", "random-pipeline-closure-seed", "A fixed seed for repeatbility of random pipeline closure.", ""); | ||
| opts.optopt("", "max-session-history", "Maximum amount of session history to store in each tab.", "256"); | ||
| opts.optmulti("Z", "debug", | ||
| "A comma-separated string of debug options. Pass help to show available options.", ""); | ||
| opts.optflag("h", "help", "Print this message"); | ||
| @@ -779,6 +784,10 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { | ||
| } | ||
| }; | ||
|
|
||
| let max_session_history = opt_match.opt_str("max-session-history").map(|max| { | ||
| max.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: --max-session-history ({})", err))) | ||
| }).unwrap_or(256); | ||
jdm
Member
|
||
|
|
||
| if opt_match.opt_present("M") { | ||
| MULTIPROCESS.store(true, Ordering::SeqCst) | ||
| } | ||
| @@ -820,6 +829,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { | ||
| userscripts: opt_match.opt_default("userscripts", ""), | ||
| user_stylesheets: user_stylesheets, | ||
| output_file: opt_match.opt_str("o"), | ||
| max_session_history: max_session_history, | ||
| replace_surrogates: debug_options.replace_surrogates, | ||
| gc_profile: debug_options.gc_profile, | ||
| load_webfonts_synchronously: debug_options.load_webfonts_synchronously, | ||
Large diffs are not rendered by default.
| @@ -901,18 +901,24 @@ impl Window { | ||
| } | ||
|
|
||
| pub fn clear_js_runtime(&self) { | ||
| // We tear down the active document, which causes all the attached | ||
| // nodes to dispose of their layout data. This messages the layout | ||
| // thread, informing it that it can safely free the memory. | ||
| self.Document().upcast::<Node>().teardown(); | ||
|
|
||
| // The above code may not catch all DOM objects | ||
| // (e.g. DOM objects removed from the tree that haven't | ||
| // been collected yet). Forcing a GC here means that | ||
| // those DOM objects will be able to call dispose() | ||
| // to free their layout data before the layout thread | ||
| // exits. Without this, those remaining objects try to | ||
| // send a message to free their layout data to the | ||
| // layout thread when the script thread is dropped, | ||
| // which causes a panic! | ||
| // The above code may not catch all DOM objects (e.g. DOM | ||
| // objects removed from the tree that haven't been collected | ||
| // yet). There should not be any such DOM nodes with layout | ||
| // data, but if there are, then when they are dropped, they | ||
| // will attempt to send a message to the closed layout thread. | ||
| // This causes memory safety issues, because the DOM node uses | ||
| // the layout channel from its window, and the window has | ||
| // already been GC'd. For nodes which do not have a live | ||
| // pointer, we can avoid this by GCing now: | ||
| self.Gc(); | ||
| // but there may still be nodes being kept alive by user | ||
| // script. | ||
| // TODO: ensure that this doesn't happen! | ||
|
|
||
| self.current_state.set(WindowState::Zombie); | ||
| *self.js_runtime.borrow_mut() = None; | ||
| @@ -1445,6 +1451,12 @@ impl Window { | ||
| None | ||
| } | ||
|
|
||
| pub fn freeze(&self) { | ||
| self.upcast::<GlobalScope>().suspend(); | ||
| // A hint to the JS runtime that now would be a good time to GC this window. | ||
| self.Gc(); | ||
jdm
Member
|
||
| } | ||
|
|
||
| pub fn thaw(&self) { | ||
| self.upcast::<GlobalScope>().resume(); | ||
|
|
||
| @@ -228,18 +228,18 @@ impl OneshotTimers { | ||
| } | ||
|
|
||
| pub fn suspend(&self) { | ||
| assert!(self.suspended_since.get().is_none()); | ||
| // Suspend is idempotent: do nothing if the timers are already suspended. | ||
cbrewster
Member
|
||
| if self.suspended_since.get().is_some() { return; } | ||
|
|
||
| self.suspended_since.set(Some(precise_time_ms())); | ||
| self.invalidate_expected_event_id(); | ||
| } | ||
|
|
||
| pub fn resume(&self) { | ||
| assert!(self.suspended_since.get().is_some()); | ||
|
|
||
| // Suspend is idempotent: do nothing if the timers are already suspended. | ||
| let additional_offset = match self.suspended_since.get() { | ||
| Some(suspended_since) => precise_time_ms() - suspended_since, | ||
| None => panic!("Timers are not suspended.") | ||
| None => return, | ||
| }; | ||
|
|
||
| self.suspension_offset.set(self.suspension_offset.get() + additional_offset); | ||
Out of curiosity, is there a reason the default is 256? That seems a bit large to me