Rust: Compiler runs out of memory in nested async/await calls since 1.46

Created on 6 Oct 2020  路  20Comments  路  Source: rust-lang/rust

I have a fairly small program (around 5k lines of code), with some heavy dependencies such as Tokio, Actix, Serde and Tokio-Tungstenite. I can't get it to compile outside of Docker because it eats all my RAM + Swap (I have 16Gb.) However, when I compile in Docker with a two steps compilation process, it takes only 1Gb.

My Cargo.toml
```[dependencies]
serde = {version = "1.0.116", features = ["derive"]}
serde_json = "1.0.58"
reqwest = {version = "0.10.8"}
futures = { version = "0.3.6", default-features = false, features = ["async-await"]}
tokio = {version = "0.2.22", features = ["rt-threaded", "macros", "tcp"]}
itertools = "0.9.0"
dotenv = "0.15.0"
futures-util = { version = "0.3.6", features = ["sink", "std"] }
tokio-tungstenite = {version = "0.10.1", features = ["connect", "tls"]}
tokio-tls = "0.3.1"
hmac = "0.9"
sha2 = "0.9.1"
mongodb = "1.1.1"
bson = "1.1.0"
actix-web = "3.1.0"
actix-rt = "1.1.1"
rustc-serialize = "0.3.24"
chrono = { version = "0.4.19", features = ["serde"] }

[profile.release]
lto = true
codegen-units = 1
opt-level = 3


My Dockerfile:

FROM rust:latest AS build_base

RUN USER=root cargo new --bin myapp
WORKDIR /myapp

COPY Cargo.toml .

RUN cargo build --release
RUN rm -f src/.rs
COPY ./src ./src
RUN rm ./target/release/deps/myapp

RUN cargo build --release

FROM rust:latest

WORKDIR /myapp

COPY --from=build_base /myapp/target/release/myapp /myapp/myapp

RUN touch .env

EXPOSE 8000

CMD ["./myapp"]



### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->

`rustc --version --verbose`:

rustc 1.49.0-nightly (a1dfd2490 2020-10-05)
binary: rustc
commit-hash: a1dfd2490a6cb456b92e469fa550dc217e20ad6d
commit-date: 2020-10-05
host: x86_64-unknown-linux-gnu
release: 1.49.0-nightly
LLVM version: 11.0
```

A-async-await C-bug E-needs-mcve I-compilemem O-linux regression-from-stable-to-stable

Most helpful comment

probably related to #75992, currently waiting for an MVCE for that issue

75992 also regressed in 1.46.0, so this is likely to be a duplicate

All 20 comments

What's the Rust version in the Docker container?

@jonas-schievink It is rust:latest, so I would assume 1.46

Does it still use 16 GB if you use that Rust version outside of the container?

@sakex: Is it possible for you to upload your repository? If not, does the high RAM usage occur when building dependencies, or when building your repository?

@jonas-schievink It is rust:latest, so I would assume 1.46

How recently have you docker pulled? Docker does not update images automatically.

@jonas-schievink, @Aaron1011, @sfackler I actually tried to compile with 1.44.0. It almost didn't use any RAM and it took way less time than I'm used to.

@Aaron1011 I can make give you access to my repo but I'd rather not share it. The code is quite complicated/messy actually.

@sfackler Given my discovery, I will not try to docker pull unless you really need some insights.

Are there any ways I could assist you in finding the regression?

Update:

I tried with 1.45.0 and 1.46.0. The bug was introduced in 1.46.0.

Is it something you are aware of?

@camelid

Update 2:

I have found the exact line that creates the problem

The original function was:

use bson::{doc};
use bson::oid::ObjectId;
use mongodb::{error::Error, Collection, options::FindOneOptions};

#[derive(Clone)]
pub struct UserService {
    collection: Collection,
}

impl UserService {
    pub async fn get_all(&self) -> Result<Vec<UserSchema>, Error> {
        let mut cursor = self.collection.find(None, None).await?; // That's the bad line
        let mut vec: Vec<UserSchema> = Vec::new();
        while let Some(result) = cursor.next().await {
            match result {
                Ok(document) => {
                    let user: UserSchema = bson::from_bson(bson::Bson::Document(document)).unwrap();
                    vec.push(user);
                }
                Err(e) => return Err(e.into()),
            }
        };
        Ok(vec)
    }
}

By removing chunks of code one by one, I isolated the offending line of code as being:

    let mut cursor = self.collection.find(None, None).await?; // That's the bad line

Which is a call to the MongoDB driver

Update 3

Lifting the code out of the function inside a .then fixes the issue:


        self.collection.find(None, None)
            .then(|mut res|  async  {
            let mut cursor = res.unwrap();
            let mut users: Vec<UserSchema> = Vec::new();
            while let Some(result) = cursor.next().await {
                match result {
                    Ok(document) => {
                        let trader: UserSchema = bson::from_bson(bson::Bson::Document(document)).unwrap();
                        users.push(trader);
                    }
                    Err(e) => return Err(e),
                }
            };
                Ok(current_traders)
        });

It is of course not so great to do that, but I hope it will help you in finding the bug

How long is your normal compile time in 1.44 ?
If possible, since we don't have access to your code,
would you mind running bisect to find a blamed commit ?
The general guide is here: https://github.com/rust-lang/cargo-bisect-rustc/blob/master/TUTORIAL.md.
The start date could be the date starting development of 1.46,
which maybe 2020-06-05.

probably related to https://github.com/rust-lang/rust/issues/75992, currently waiting for an MVCE for that issue

@lzutao It takes around 1:45 minutes (in debug with dependencies cached)

I will run the bisection now

@lzutao It takes around 1:45 minutes (in debug with dependencies cached)

Took much longer than I thought, so bisection is possible, but you might not want
to do it in your local host.

@lzutao I need to go anyway, so I'll let it run for a few hours, I'll report if I find something

The command:
cargo bisect-rustc --start=2020-07-01 --end=2020-10-07

probably related to #75992, currently waiting for an MVCE for that issue

75992 also regressed in 1.46.0, so this is likely to be a duplicate

@lzutao


Regression in 0a49057dd35d9bd2fcc9760a054809c30eee2a58


searched nightlies: from nightly-2020-08-13 to nightly-2020-08-14
regressed nightly: nightly-2020-08-14
searched commits: from https://github.com/rust-lang/rust/commit/576d27c5a6c80cd39ef57d7398831d8e177573cc to https://github.com/rust-lang/rust/commit/81dc88f88f92ba8ad7465f9cba10c12d3a7b70f1
regressed commit: https://github.com/rust-lang/rust/commit/0a49057dd35d9bd2fcc9760a054809c30eee2a58


bisected with cargo-bisect-rustc v0.5.2

Host triple: x86_64-unknown-linux-gnu
Reproduce with:

cargo bisect-rustc --start=2020-08-13 --end=2020-08-14 

This is the same regressed commit as #75992, so closing as a duplicate of #75992.

Thank you very much @sakex for taking the time to bisect this!

Duplicate of #75992.

Hmm, I thought that would mark it in GitHub...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alexcrichton picture alexcrichton  路  240Comments

cramertj picture cramertj  路  512Comments

nikomatsakis picture nikomatsakis  路  236Comments

nikomatsakis picture nikomatsakis  路  274Comments

nikomatsakis picture nikomatsakis  路  412Comments