maaaaz / webscreenshot

A simple script to screenshot a list of websites
GNU Lesser General Public License v3.0
653 stars 162 forks source link

Memory Exhaustion possibly due to unfinished PhantomJS Processes #32

Closed fededamian closed 4 years ago

fededamian commented 4 years ago

While running webscreenshot on a Digital Ocean Ubuntu Box with 2 GB of RAM on a list of approximately 7500 valid HTTP servers, the tool starts working correctly with an overall 250-300 MB of memory compsumtion on the whole OS.

As the tool continues working, that memory compsumption increases over time until there isn't any more available to use and the tool starts sending errors. I took a screenshot of htop, which I'm attaching, during execution while everything still works okay and I notice docens of phantomjs processes, although I set the tool to run just 1 worker. If I kill all these processes everything goes back to normal.

The command used was the following:

webscreenshot --no-xserver -r phantomjs -w 1 --window-size 640,360 -o output_dir -i servers_file

That was ran inside a screen, although I don't think that would make a difference.

The could be an issue in the process of finishing phantomjs processes. It would be great if this could be reviewed.

Thanks in advance,

Htop screenshot:

Screen Shot 2019-10-31 at 14 12 33

fededamian commented 4 years ago

I am trying this again without using screen to see if the issue persists while running the tool directly. Also, I can confirm that after killing the webscreenshot process, the phantomjs ones are not killed, and I had to manually kill them through:

ps aux | grep phantomjs | grep -v grep | awk '{print $2}' | xargs kill -9

That returned the memory status back to normal.

maaaaz commented 4 years ago

Hello @fededamian, From what I understand it might come from a memory leak of phantomjs ? It's not the Python process itself that leaks ?

By the way, which Python precise version are you using ?

fededamian commented 4 years ago

Without using screen the issue persists.

These are the outputs for the versions I am running, sorry I omitted that before:

# uname -a
Linux cloud 4.15.0-66-generic #75-Ubuntu SMP Tue Oct 1 05:24:09 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

# python --version
Python 2.7.15+

# python3 --version
Python 3.6.8

# webscreenshot -h | head -1
webscreenshot.py version 2.5

I don't know if it could be due to a PhantomJS memory leak. What I noticed is that a lot of the system calls made to phantomJS create these processes that, after webscreenshot even finishes, still persist. It may be due to the way the syscall to phantomJS is done on the Python script?

Also, it may be interesting to know if this behaviour is also replicated in other people's setups. Maybe nobody noticed this before because, if you have at least 4 GB of RAM, that would probably be okay to screenshot more than 10k HTTP servers on a single run even with the increasing rate in the memory I noticed. This could be monitored through htop by checking if the memory increases consistently during a long webscreenshot execution, and also check if the phantomJS processes remain after the tool finished.

maaaaz commented 4 years ago

There's 2 termination cases for a phantomjs instance launched by webscreenshot:

I see in your htop that Python 2 is used: could you try to install webscreenshot in a Python 3 environment (pip3 install webscreenshot) and perform the same test ?

fededamian commented 4 years ago

The issue is also present using Python3. This time, I think by luck, the webscreenshot run was able to complete. After being finished, my memory is completly occupied:

# free -h
              total        used        free      shared  buff/cache   available
Mem:           1.9G        1.9G         51M        924K         32M         12M
Swap:            0B          0B          0B

And there are 15 PhantomJS processes left there running unclosed:

# ps aux | grep phantomjs | grep -v grep | wc -l
15

There might be a condition in web screenshot in which the PhantomJS is never finished and is still on background consuming RAM. The more HTTP servers you scan, the more likely this condition may appear.

Below is the output of processes left running taken from ps. The subdomains that were halted in there can be seen. If you want me to provide you with the full list of HTTP servers I'm testing in a private manner I can.

/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://030.localization.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_030.localization.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://pdf.localization.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_pdf.localization.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://perf-ecms-alph.stage.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_perf-ecms-alph.stage.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://refer.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_refer.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://res.localization.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_res.localization.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://resources.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_resources.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://business.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_business.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=https://000.localization.att.com:443 output_file=/root/bb/programs/att/domains/att.com/screenshots/https_000.localization.att.com_443.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=https://010.localization.att.com:443 output_file=/root/bb/programs/att/domains/att.com/screenshots/https_010.localization.att.com_443.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://cd2migration.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_cd2migration.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://clouduser.synaptic.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_clouduser.synaptic.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://cmp.localization.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_cmp.localization.att.com_80.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=https://dnf.localization.att.com:443 output_file=/root/bb/programs/att/domains/att.com/screenshots/https_dnf.localization.att.com_443.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=https://dpt.eia.att.com:443 output_file=/root/bb/programs/att/domains/att.com/screenshots/https_dpt.eia.att.com_443.png width=640 height=360 format=png quality=75
/usr/lib/phantomjs/phantomjs --ignore-ssl-errors=true --ssl-protocol=any --ssl-ciphers=ALL /usr/local/lib/python3.6/dist-packages/webscreenshot/webscreenshot.js url_capture=http://localization.att.com:80 output_file=/root/bb/programs/att/domains/att.com/screenshots/http_localization.att.com_80.png width=640 height=360 format=png quality=75
fededamian commented 4 years ago

There are also lots of Xvfb processes left running, which also consume lots of RAM. Take into account that webscreenshot is not running anymore and all these was left from its execution. After killing all the PhantomJS and Xvfb Processes RAM goes back to normal:

Xvfb :121 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.fFWunS/Xauthority
Xvfb :122 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.RFp0iv/Xauthority
Xvfb :123 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.VwJLba/Xauthority
Xvfb :124 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.PO88bG/Xauthority
Xvfb :99 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.qbz30S/Xauthority
Xvfb :133 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.hVsOPf/Xauthority
Xvfb :134 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.vzPbb0/Xauthority
Xvfb :125 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.sI5cRM/Xauthority
Xvfb :126 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.kZu0VP/Xauthority
Xvfb :135 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.AGJvNw/Xauthority
Xvfb :136 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.QGlf4j/Xauthority
Xvfb :137 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.H0WpUy/Xauthority
Xvfb :138 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.vMlzvA/Xauthority
Xvfb :139 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.DMIvhl/Xauthority
Xvfb :140 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.rT3S35/Xauthority
Xvfb :127 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.byckkq/Xauthority
Xvfb :128 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.RXkyiT/Xauthority
Xvfb :100 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.ImyE24/Xauthority
Xvfb :141 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.0G34di/Xauthority
Xvfb :142 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.AwkmeH/Xauthority
Xvfb :101 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.oZgHy8/Xauthority
Xvfb :143 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.fPGPFF/Xauthority
Xvfb :144 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.hmkhvk/Xauthority
Xvfb :102 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.Zmmcmh/Xauthority
Xvfb :103 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.KkKW6I/Xauthority
Xvfb :145 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.E9Zx2q/Xauthority
Xvfb :104 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.1VS0Dy/Xauthority
Xvfb :105 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.Hjo8yK/Xauthority
Xvfb :106 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.xfbuBW/Xauthority
Xvfb :107 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.H4gEsc/Xauthority
Xvfb :108 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.UZYjWy/Xauthority
Xvfb :109 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.7rVClw/Xauthority
Xvfb :110 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.lr8wa8/Xauthority
Xvfb :146 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.DRh9dF/Xauthority
Xvfb :147 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.Va98m8/Xauthority
Xvfb :148 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.tzfmxv/Xauthority
Xvfb :111 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.CnpqNX/Xauthority
Xvfb :112 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.IKCnek/Xauthority
Xvfb :113 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.wGCbj4/Xauthority
Xvfb :114 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.NfoJ64/Xauthority
Xvfb :149 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.IAZWNC/Xauthority
Xvfb :150 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.ejIFCz/Xauthority
Xvfb :151 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.3zSZFM/Xauthority
Xvfb :115 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.8djQ8q/Xauthority
Xvfb :152 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.zZLr4C/Xauthority
Xvfb :116 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.31NKUv/Xauthority
Xvfb :153 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.QT17rT/Xauthority
Xvfb :154 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.DBNasx/Xauthority
Xvfb :155 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.IPUBxj/Xauthority
Xvfb :156 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.w2Y2I8/Xauthority
Xvfb :157 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.3mlLSL/Xauthority
Xvfb :158 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.LxGJMb/Xauthority
Xvfb :159 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.UkWRIT/Xauthority
Xvfb :160 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.ItR9ad/Xauthority
Xvfb :130 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.hXDRM3/Xauthority
Xvfb :161 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.3MuC7y/Xauthority
Xvfb :162 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.C74TUk/Xauthority
Xvfb :163 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.WlYh76/Xauthority
Xvfb :164 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.CjHYmf/Xauthority
Xvfb :165 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.UwyAAi/Xauthority
Xvfb :166 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.7ZbwPs/Xauthority
Xvfb :167 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.yugcya/Xauthority
Xvfb :168 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.cfpE3l/Xauthority
Xvfb :169 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.H6nb23/Xauthority
Xvfb :170 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.Mj5jLF/Xauthority
Xvfb :171 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.26rFGc/Xauthority
Xvfb :172 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.fNFpA9/Xauthority
Xvfb :173 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.DfUjyZ/Xauthority
Xvfb :178 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.TQCTje/Xauthority
Xvfb :131 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.Qk7JFP/Xauthority
Xvfb :174 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.1FAMmd/Xauthority
Xvfb :175 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.QUd5kj/Xauthority
Xvfb :176 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.vfvurO/Xauthority
Xvfb :177 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.b80QOs/Xauthority
Xvfb :179 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.NPoDg6/Xauthority
Xvfb :180 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.Gz0zVQ/Xauthority
Xvfb :181 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.gpK1bu/Xauthority
Xvfb :182 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.Z0ghP8/Xauthority
Xvfb :117 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.wxDEYW/Xauthority
Xvfb :183 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.iwmJ0X/Xauthority
Xvfb :184 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.bygwD3/Xauthority
Xvfb :185 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.GHpwuf/Xauthority
Xvfb :186 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.nJmK2A/Xauthority
Xvfb :187 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.mvuh1c/Xauthority
Xvfb :188 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.ReeHo4/Xauthority
Xvfb :189 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.eNxrDn/Xauthority
Xvfb :190 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.FoLXbR/Xauthority
Xvfb :191 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.1hjI8T/Xauthority
Xvfb :192 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.HVta4t/Xauthority
Xvfb :193 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.gZMOCA/Xauthority
Xvfb :118 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.G9qZWU/Xauthority
Xvfb :194 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.CBkDbp/Xauthority
Xvfb :195 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.y7Zx1v/Xauthority
Xvfb :119 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.GFaoDR/Xauthority
Xvfb :196 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.yd2GXi/Xauthority
Xvfb :197 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.X0KrFY/Xauthority
Xvfb :198 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.ZbUkCs/Xauthority
Xvfb :199 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.UX5Csy/Xauthority
Xvfb :200 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.M4CuIx/Xauthority
Xvfb :201 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.KtdZp5/Xauthority
Xvfb :202 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.R0ICZw/Xauthority
Xvfb :203 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.uKngCc/Xauthority
Xvfb :204 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.bnidIJ/Xauthority
Xvfb :205 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.tvGScP/Xauthority
Xvfb :120 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.gRqsQo/Xauthority
Xvfb :129 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.rtciOs/Xauthority
Xvfb :132 -screen 0 640x480x16 -nolisten tcp -auth /tmp/xvfb-run.30UnU4/Xauthority
maaaaz commented 4 years ago

So it seems to be a common issue for xvfb-run :

One solution that I will try will be to SIGKILL (on Linux) the process group:

os.killpg(PGID, signal.SIGKILL)

The other one would be to not call xvfb-run but directly xvfb: https://unix.stackexchange.com/a/311599

maaaaz commented 4 years ago

Fixed in v2.8. Child processes have been grouped in a session per URL to screenshot, the SIGKILL signal in case if timeout kills the session, so all descendants.

I let you do some tests and use that command to investigate:

$ ps -ejf | egrep "webscreenshot|Xvfb|STIME|convert"

I have read this resources to patch:

I could have had patched with a less elegant solution