1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-11 01:39:33 +00:00

fix continous growth of app data in pooled requests (#1609)

fixes #1606
fixes #1607
This commit is contained in:
Rob Ede 2020-07-18 16:17:00 +01:00 committed by GitHub
parent 2fd96c03e5
commit 971ba3eee1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 8 deletions

View file

@ -1,6 +1,10 @@
# Changes
## Unreleased - 2020-xx-xx
### Fixed
* Memory leak of app data in pooled requests. [#1609]
[#1609]: https://github.com/actix/actix-web/pull/1609
## 3.0.0-beta.1 - 2020-07-13

View file

@ -10,6 +10,7 @@ use actix_router::{Path, ResourceDef, ResourceInfo, Router, Url};
use actix_service::boxed::{self, BoxService, BoxServiceFactory};
use actix_service::{fn_service, Service, ServiceFactory};
use futures_util::future::{join_all, ok, FutureExt, LocalBoxFuture};
use tinyvec::tiny_vec;
use crate::config::{AppConfig, AppService};
use crate::data::{DataFactory, FnDataFactory};
@ -245,7 +246,7 @@ where
inner.path.reset();
inner.head = head;
inner.payload = payload;
inner.app_data.push(self.data.clone());
inner.app_data = tiny_vec![self.data.clone()];
req
} else {
HttpRequest::new(

View file

@ -276,6 +276,7 @@ impl HttpMessage for HttpRequest {
impl Drop for HttpRequest {
fn drop(&mut self) {
// if possible, contribute to current worker's HttpRequest allocation pool
if Rc::strong_count(&self.0) == 1 {
let v = &mut self.0.pool.0.borrow_mut();
if v.len() < 128 {
@ -340,25 +341,32 @@ impl fmt::Debug for HttpRequest {
}
}
/// Request's objects pool
/// Slab-allocated `HttpRequest` Pool
///
/// Since request processing may yield for asynchronous events to complete, a worker may have many
/// requests in-flight at any time. Pooling requests like this amortizes the performance and memory
/// costs of allocating and de-allocating HttpRequest objects as frequently as they otherwise would.
///
/// Request objects are added when they are dropped (see `<HttpRequest as Drop>::drop`) and re-used
/// in `<AppInitService as Service>::call` when there are available objects in the list.
///
/// The pool's initial capacity is 128 items.
pub(crate) struct HttpRequestPool(RefCell<Vec<Rc<HttpRequestInner>>>);
impl HttpRequestPool {
/// Allocates a slab of memory for pool use.
pub(crate) fn create() -> &'static HttpRequestPool {
let pool = HttpRequestPool(RefCell::new(Vec::with_capacity(128)));
Box::leak(Box::new(pool))
}
/// Get message from the pool
/// Re-use a previously allocated (but now completed/discarded) HttpRequest object.
#[inline]
pub(crate) fn get_request(&self) -> Option<HttpRequest> {
if let Some(inner) = self.0.borrow_mut().pop() {
Some(HttpRequest(inner))
} else {
None
}
self.0.borrow_mut().pop().map(HttpRequest)
}
/// Clears all allocated HttpRequest objects.
pub(crate) fn clear(&self) {
self.0.borrow_mut().clear()
}