This article is participating in “Java Theme Month – Java Development Practice”, for details: juejin.cn/post/696826…

This is the 8th day of my participation in Gwen Challenge

Linux processes and threads

Regardless of how the threading model and implementation is defined in Java or any other language, the notion of threads (LWP: Lightweight threading technology mapped to kernel threads) being ascribed to the operating system level from an underlying perspective is ignored.

Richard Stevens’ Description of threads

fork is expensive. Memory is copied from the parent to the child, all descriptors are duplicated in the child, and so on. Current implementations use a technique called copy-on-write, Which avoids a copy of the parent’s data space to the child until the child needs its own copy. regardless of this optimization, fork is expensive. IPC is required to pass information between the parent and child after the fork. Passing information from the parent to the child before the fork is easy, Since the child starts with a copy of the parent’s data space and with a copy of all the parent’s descriptors. But, returning information from the child to the parent takes more work. Threads help with both problems. Threads are Sometimes called lightweight processes since a thread is “lighter weight” than a process. Thread creation can be 10-100 times faster than process creation. All threads within a process share the same global memory. This makes the sharing of information easy between the threads, but along with this simplicity comes the problem.

Richard Stevens’ Description of threads

  • In Linux, processes are fork and threads are clone.

  • Ps-ef shows a list of processes, and threads can be viewed through Ps-ELF.

  • Using the top command, you can also switch to the thread view using the H switch.

  • In terms of the Java thread model, the specification does not specify a mapping between Java threads and system threads, but the current common implementation is one-to-one.

reference

Openjdk.java.net/groups/hots…

Troubleshooting Methods

If Java thread cannot be created, an error is reported

The Exception in the thread "main" Java. Lang. OutOfMemoryError: unable to create new native threadCopy the code

Here are some common causes of problems

Memory is too small

Creating a thread in Java consumes a certain amount of stack space. The default stack space is 1M(which can be adjusted depending on the application). Stackoverflowerrors can occur if the stack space is too small or if the recursive call is too deep.

For a process, assuming a certain amount of available memory, the more space allocated to the heap, the less space left for the stack.

  • This limit is common in 32-bit Java applications, with 4 gb of process space and 2 gb of user space (3 gb under Linux, so the heap can usually be larger).

    • Subtract the heap size (range specified by -xms, -xmx)

    • Remove non-heap space (where the permanent generation is sized by PermSize, MaxPermSize, MetaSpace in Java8, and the default size is not limited).

    • Subtract the virtual machine’s own consumption.

  • All that is left is stack space, and assuming 300M is left, there is a theoretical limit of 300 threads (-xSS1m).

However, for 64-bit applications, the process space is nearly infinite, so you can ignore this problem.

Ulimit limit

The number of threads is also limited by the system, which can be viewed by using ulimit-a.

Ss64.com/bash/ulimit…

caixj@Lenovo-PC:~$ ulimit -a

core file size          (blocks, -c) 0

data seg size          (kbytes, -d) unlimited

scheduling priority            (-e) 0

file size              (blocks, -f) unlimited

pending signals                (-i) 7823

max locked memory      (kbytes, -l) 64

max memory size        (kbytes, -m) unlimited

open files                      (-n) 1024

pipe size            (512 bytes, -p) 8

POSIX message queues    (bytes, -q) 819200

real-time priority              (-r) 0

stack size              (kbytes, -s) 8192

cpu time              (seconds, -t) unlimited

max user processes              (-u) 7823

virtual memory          (kbytes, -v) unlimited

file locks                      (-x) unlimited

Copy the code
The relevant limitations are
  • Max Memory size: The maximum memory limit. On 64-bit systems, it is usually set to Unlimited

  • Max user processes: Maximum number of processes (including threads) per user

  • Virtual Memory – Virtual memory limit, usually set to Unlimited on 64-bit systems

These parameters can be achieved by the ulimit command (temporary effect for the current user) or the configuration file/etc/security/limits the conf (permanent). To check whether the limits of a process are in effect, run /proc/pid/limits to check the runtime status.

Limit of the sys.kernel.threads-max parameter

https://www.kernel.org/doc/Documentation/sysctl/kernel.txt This value controls the maximum number of threads that can be  created using fork(). During initialization the kernel sets this value such that even if the maximum number of threads is created, the thread structures occupy only a part (1/8th) of the available RAM pages. The minimum value that can be written to threads-max is 20. The maximum value that can be written to threads-max is given by the constant FUTEX_TID_MASK (0x3fffffff). If a value outside of this range is written to threads-max an error EINVAL occurs. The value written is checked against the available RAM pages. If the thread structures would occupy too much (more than 1/8th) of the available RAM pages threads-max is reduced accordingly.Copy the code

Represents the total thread limit for the system globally. The Settings are as follows:

Runtime restriction, effective temporarily

echo 999999 > /proc/sys/kernel/threads-max

Change the /etc/sysctl.conf file to take effect permanently

sys.kernel.threads-max = 999999

The parameter sys.kernel.pid_max is limited

https://www.kernel.org/doc/Documentation/sysctl/kernel.txt

PID allocation wrap value.  When the kernel's next PID value

reaches this value, it wraps back to a minimum PID value.

PIDs of value pid_max or larger are not allocated.

Copy the code

Represents a limit on the global PID number value for the system. The Settings are as follows:

Runtime restriction, effective temporarily

echo 999999 > /proc/sys/kernel/pid_max

Change the /etc/sysctl.conf file to take effect permanently

sys.kernel.pid_max = 999999

Parameter sys.vm.max_map_count limit

https://www.kernel.org/doc/Documentation/sysctl/vm.txt

This file contains the maximum number of memory map areas a process

may have. Memory map areas are used as a side-effect of calling

malloc, directly by mmap, mprotect, and madvise, and also when loading

shared libraries.

While most applications need less than a thousand maps, certain

programs, particularly malloc debuggers, may consume lots of them,

e.g., up to one or two maps per allocation.

The default value is 65536.
Copy the code

Represents the limit on the amount of memory-mapped space that a single process can use. The Settings are as follows:

Mode 1 Runtime restriction takes effect temporarily

echo 999999 > /proc/sys/vm/max_map_count

Method 2 Modify the /etc/sysctl.conf file to take effect permanently

sys.vm.max_map_count = 999999

In the case of other resources available to a single vm can turn on the maximum number of threads is half the value, can through the cat/proc/PID/maps | wc -l view currently use the size of the map.

As for why only half, combined with some materials and source code analysis:

A common warning message goes like this, see

JavaThread::create_stack_guard_pages()
Attempt to protect stack guard pages failed.
Attempt to deallocate stack guard pages failed.
Copy the code

See current_stack_region icon (), combined with the related solution R big Shih: hllvm.group.iteye.com/group/topic…

As shown below, a normal Java thread would include a Glibc Guard Page and HotSpot Guard Pages, JavaThread:: create_stack_guard_Pages () is used to create HotSpot Guard Pages. You can also see from /proc/pid/maps that adding a thread increases the mapping space for 2 addresses.

// Java thread: // // Low memory addresses // +------------------------+ // | |\ JavaThread created by VM does not have glibc // | glibc  guard page | - guard, attached Java thread usually has // | |/ 1 page glibc guard. // P1 +------------------------+ Thread::stack_base() - Thread::stack_size() // | |\ // | HotSpot Guard Pages | - red and yellow pages // | |/ // +------------------------+ JavaThread::stack_yellow_zone_base() // | |\ // | Normal Stack | - // | |/ // P2 +------------------------+ Thread::stack_base() // // Non-Java thread: // // Low memory addresses // +------------------------+ // | |\ // | glibc guard page | - usually 1 page // | |/ // P1 +------------------------+ Thread::stack_base() - Thread::stack_size() // | |\ // | Normal Stack | - // | |/ // P2 +------------------------+ Thread::stack_base() // // ** P1 and size ( P2 = P1 - size) are the address and stack size returned from // pthread_attr_getstack()Copy the code