Troubleshooters.Com and Linux Library present:

Fix: GUI Windows Won't Open

See the Troubleshooters.Com Bookstore.

Introduction

This "cannot open any more GUI windows" symptom is often accompanied by the error message "Maximum number of clients reached", which can be viewed on the terminal on which you tried to run the program whose window won't open. This document is about inability to open windows, accompanied by the error message, assuming the error message is there for you to see.

The maximum number of clients is surprisingly low: In the hundreds or low thousands. Given that many programs, such as Chromium, use tens of clients, it doesn't take much to use up all your clients. However, if you need Chromium (or Google Chrome), you need it. Firefox and the rest of the browsers all have their own problems, either incompatiblity, bloatitude, or both. So you have one of two choices:

  1. Raise the maximum number of clients allowed, which is beyond the scope of this document.
  2. Lower the number of clients currently in use, which is what this document is all about.

The usual cause is a few defective or overbloated applications that are hogging too many clients, making it impossible to run all the necessary applications. On my computer, these applications are:

  1. reminders.py: A badly written, zombie creating program written by me.
  2. chromium, Chrome based browsers, and some other browsers.
  3. dbus-daemon: An overcomplexificated client-shedding mess.
  4. sakura: An otherwise great terminal program that runs three clients for every window it opens. Luckily, opening a tab on an existing Sakura window produces no additional clients.

How I Fixed My Situation

Here's how I fixed my particular situation:

Diagnostics

Your first job is to acquire and observe the symptom. On a terminal already running, run another small GUI program, and if that program's window doesn't appear, scan the output on the terminal for "Maximum number of clients reached". If you see that string, you're dealing with this problem. Next step is to get a rough estimate of its magnitude with the following command:

lsof -U | wc -l

The preceding gives you the number of open Unix sockets. Observe that it varies according to which user issues it: User root yields a higher number. I don't know which user gives the more indicative number, but for now I'm using the user who encountered the symptom, which in my case is user slitt.

Note:

"Unix sockets" and what X calls "clients" are related. I'm not sure how they're related, but my subjective findings have been that as Unix sockets increase, so do window-stopping "clients".

Next is an 87 line Python program to get an idea of which programs and processes are hogging the most Unix sockets. It's actually two reports. The first breaks down only by executable name, sorted by number of sockets used. The grand total is on top, on the report's title line.

The second report is similar, except broken down by PID, so if necessary you can find which instance of a program is creating too many clients. The source of this program, whose name is lsof_anal.py, follows:

#!/usr/bin/python
import sys
import subprocess
import re

def get_sock_list():
    with subprocess.Popen(
            ["/usr/bin/lsof", "-U"],
            stdout=subprocess.PIPE,
            text=True
            ) as proc:
        lines = proc.stdout.readlines()

    return_lines = []
    lineno = 0
    for line in lines:
        if lineno > 0:
            fields = line.split()
            return_lines.append(
                '{}  {}'.format(
                fields[0].ljust(10, ' '),
                fields[1].rjust(5, '0')
                )
                )
        lineno += 1
    return return_lines

def make_report_lines(lines):
    prevline = "            "
    occurrences = 0
    total_occurrences = 0
    firstime = True
    report_lines = []
    for line in lines:
        if firstime:
            firstime = False
            continue
        if line != prevline:
            st=str(occurrences).rjust(7, ' ') 
            st += "  "
            st += prevline
            report_lines.append(st)
            prevline = line
            occurrences = 1
        if line == prevline:
            occurrences += 1
            total_occurrences += 1
    st="   {} GRAND TOTAL"
    st=st.format(str(total_occurrences))
    report_lines.append(st)
    return sorted(report_lines,reverse=True)
    
def remove_pids(lines):
    ss=0
    for line in lines:
        fields = line.split(' ', 1)
        lines[ss] = fields[0]
        ss += 1
    return lines

def print_array(arr):
    for line in arr:
        print(line)

def main():
    socklist = []
    socklist = get_sock_list()
    socklist = sorted(socklist)

    by_program_and_pid = \
            make_report_lines(socklist)

    socklist = remove_pids(socklist)
    socklist = sorted(socklist)
    by_program = \
            make_report_lines(socklist)
    print("BY PROGRAM REPORT:", end='')
    print_array(by_program)
    print("\n\n\n")

    print("BY PROGRAM AND PID REPORT: ",
          end='')

    print_array(by_program_and_pid)

if __name__ == '__main__':
    main()

On my computer a few minutes ago, the preceding program output the following:

[slitt@mydesk lsof_anal]$ ./lsof_anal.py
BY PROGRAM REPORT:   181 GRAND TOTAL
     80  chromium
     38  dbus-daem
     10  gvim.warn
      8  xterm
      7  claws-mai
      5  lxtermina
      5  bluefish
      4  mpv
      4  gnome-key
      4  chrome_cr
      4  at-spi2-r
      3  xdg-docum
      3  xdg-deskt
      3  dunst
      3  dbus-laun
      2  xinit
      2  xdg-permi
      2  parcellit
      2  openbox
      2  gvfsd-fus
      2  gvfsd
      2  goa-ident
      2  goa-daemo
      2  fetchmail
      2  dconf-ser
      0              




BY PROGRAM AND PID REPORT:    181 GRAND TOTAL
     27  dbus-daem   01541
     24  chromium    17543
     13  chromium    17755
     12  dbus-daem   01612
      7  claws-mai   09275
      7  chromium    17836
      7  chromium    00708
      6  chromium    17595
      6  chromium    17584
      5  lxtermina   14701
      5  chromium    28776
      5  chromium    10911
      5  chromium    00396
      5  chromium    00312
      5  bluefish    11512
      4  gvim.warn   23967
      4  gvim.warn   09885
      4  gvim.warn   03695
      4  gnome-key   25872
      4  at-spi2-r   01714
      3  zeitgeist   13252
      3  zeitgeist   01518
      3  xdg-docum   01687
      3  xdg-deskt   25864
      3  dunst       01622
      3  dbus-laun   01540
      3  chromium    17554
      3  chromium    17552
      3  chromium    17551
      3  chrome_cr   17545
      2  xterm       22013
      2  xterm       21028
      2  xterm       20068
      2  xterm       18360
      2  xterm       03940
      2  xterm       01885
      2  xterm       00768
      2  xinit       01401
      2  xdg-permi   01692
      2  parcellit   01521
      2  openbox     01420
      2  mpv         12150
      2  mpv         08310
      2  mpv         07460
      2  gvfsd-fus   01638
      2  gvfsd       01628
      2  goa-ident   01674
      2  goa-daemo   01666
      2  fetchmail   03001
      2  dconf-ser   07064
      2  chrome_cr   17547
      0              

Use the output of the preceding to find out which programs are hogging clients, and which processes contribute to the hogging. While you're at it, now's a great time to find all zombie processes and kill them, or if you can't kill them, investigate and kill their parents. The following command shows all your zombies:

ps -ao stat,pid,ppid,command | grep -i ^z

Try killing them by their PID. If that doesn't work, investigate their PPID by grepping for it (the number right after the PID in the output of the preceding command). A great shellscript for investigating a ppid is the following:

#!/bin/ksh
ps -ao pid,ppid,stat,command | head -n1
ps -ao pid,ppid,stat,command | grep "^$1"

Just use the PPID of the zombie as the argument for this shellscript.

As Time Goes By

As time goes by you'll find patterns and correlations to your inability to open new GUI windows. Whenever confronted with this symptom, run lsof_eval.py, the Linux socket reporting program, to see patterns. What's the grand total of sockets reported by the program? Looking at the "by program" report, what programs seem to be opening the most Unix sockets? Check out the "by program and pid" report to see whether one particular process has a lot of Unix sockets open. Use the zombie finding shellscript described in the preceding section to find all zombies, and kill them if you can. Once you can open GUI windows again, recheck all these things to get an idea of the the number of open Unix sockets and other information contributing to inability to open further GUI windows.

As time goes by and you get familiar with the patterns, you might be able to make a cron triggered shellscript, or systemd timer triggered if you drive on that side of the road, to get rid of known pests like my known-bad reminders.py, and perhaps warning you of other problems before creating windows becomes impossible.

Summary

Sometimes it becomes impossible to open further GUI Windows. Sometimes, if you try to run window-producing programs from a command prompt on a GUI terminal, you're greeted with a bunch of error messages including the dreaded "Maximum number of clients reached". When you see this error message, you know you're dealing with the problems discussed in this document.

The best way of handling this is to use the diagnostic shellscripts and Python programs described in this document, and perhaps others of your own making, to get familiar with the problem and keep it under control.