Ullaakut / nmap

Idiomatic nmap library for go developers
MIT License
922 stars 102 forks source link

Memory Usage is too high when using Progress(...) #117

Open gnuletik opened 1 year ago

gnuletik commented 1 year ago

When running nmap with service info and progression, the memory usage is above 1GB in around 10 minutes. Which seems quite high.

    scanner, err := nmap.NewScanner(
        ctx,
        nmap.WithTargets(target),
        nmap.WithPorts("0-6000"),
        nmap.WithServiceInfo(),
    )
    if err != nil {
        return fmt.Errorf("nmap.NewScanner: %w", err)
    }

    progress := make(chan float32)

    result, warnings, err := scanner.Progress(progress).Run()

I see multiple way to reduce the memory usage:

Do you see other possible fixes?

Thanks!

Ullaakut commented 1 year ago

I don't think the gigabyte of used RAM is due to the task progress slice, or to the output kept in memory. The nmap outputs amounts to maybe a few megabytes on a very large scan, and 10 minutes of progress reports every 100ms would mean 6000 structs that are each a few bytes, so likely only takes a few kilobytes.

The ram usage most likely comes from the dependencies of this library and Go's policy for garbage collection. 1GB usage doesn't necessarily mean that the program is using 1GB right now, it only means that it reserved 1GB (probably because the total allocations amount to 1GB) but if the system tries to get some of that memory back, the garbage collector will free what's not in use.

I could do a proper benchmark if this becomes a real issue, but so far from my testing the consumption seems to be nothing out of the ordinary.

gnuletik commented 1 year ago

Thanks for the feedback!

When removing the scanner.Progress(...) configuration, the memory usage is kept below a 100MB after 10 minutes, so that's why I thought that this is linked to the task progress slice.

About the Go's policy for garbage collection: the issue occurred in a container / Kubernetes environment with a memory request and limit set to 1GB. During multiple runs, the container was OOMKilled, which means that the real memory used was above 1GB.

I'll try to use the GOMEMLIMIT env variable to set configure the GC.

Ullaakut commented 1 year ago

Ah, that is interesting 🤔 There is then indeed an issue with the progress mode. We need to look into it! Will update the labels accordingly.

Ullaakut commented 1 year ago

TODO, in case someone else picks it up:

gnuletik commented 1 year ago

I made more tests with nmap.NewScanner(ctx, nmap.WithPorts("-"), nmap.WithServiceInfo())

I run a first scan without nmap.Progress(...).

Here is the memory usage:

Screenshot 2023-07-17 at 16 58 42

Then I run another container with:

Here is the memory usage:

Screenshot 2023-07-17 at 17 01 07

The container ended with a OOMKilled error from Kubernetes.

Ullaakut commented 1 year ago

This looks like a serious issue indeed. Thanks for the details! I'll try to find some time to fix this.

llwq123456 commented 1 week ago

@Ullaakut hello, Are SIGUSR1 and SIGUSR2 signals used in this project?

Ullaakut commented 3 days ago

@llwq123456 No