jvm支持最大线程数简单测试

最近想测试下Openfire下的最大并发数,需要开大量线程来模拟客户端。对于一个JVM实例到底能开多少个线程一直心存疑惑,所以打算实际测试下,简单google了把,找到影响线程数量的因素有下面几个:


-Xms


intial java heap size


-Xmx


maximum java heap size


-Xss


the stack size for each thread


系统限制


系统最大可开线程数

测试程序如下: Java代码 :

import java.util.concurrent.atomic.AtomicInteger;  

public class TestThread extends Thread {
  private static final AtomicInteger count = new AtomicInteger();  

  public static void main(String[] args) {
    while (true)
      (new TestThread()).start();  

  }  

  @Override
  public void run() {
    System.out.println(count.incrementAndGet());  

    while (true)
      try {
        Thread.sleep(Integer.MAX_VALUE);
      } catch (InterruptedException e) {
        break;
      }
  }
}  

测试环境: 系统:Ubuntu 10.04 Linux Kernel 2.6 (32位)
内存:2G
JDK:1.7

测试结果:
Ø 不考虑系统限制


-Xms


-Xmx


-Xss


结果


1024m


1024m


1024k


1737


1024m


1024m


64k


26077


512m


512m


64k


31842


256m


256m


64k


31842

在创建的线程数量达到31842个时,系统中无法创建任何线程。

由上面的测试结果可以看出增大堆内存(-Xms,-Xmx)会减少可创建的线程数量,增大线程栈内存(-Xss,32位系统中此参数值最小为60K)也会减少可创建的线程数量

Ø 结合系统限制

线程数量31842的限制是是由系统可以生成的最大线程数量决定的:/proc/sys/kernel/threads-max,可其默认值是32080。修改其值为10000:echo 10000 > /proc/sys/kernel/threads-max,修改后的测试结果如下:


-Xms


-Xmx


-Xss


结果


256m


256m


64k


9761

这样的话,是不是意味着可以配置尽量多的线程?再做修改:echo 1000000 > /proc/sys/kernel/threads-max,修改后的测试结果如下:


-Xms


-Xmx


-Xss


结果


256m


256m


64k


32279


128m


128m


64k


32279

发现线程数量在达到32279以后,不再增长。查了一下,32位Linux系统可创建的最大pid数是32678,这个数值可以通过/proc/sys/kernel/pid_max来做修改(修改方法同threads-max),但是在32系统下这个值只能改小,无法更大。在threads-max一定的情况下,修改pid_max对应的测试结果如下:


pid_max


-Xms


-Xmx


-Xss


结果


1000


128m


128m


64k


582


10000


128m


128m


64k


9507

在Windows上的情况应该类似,不过相比Linux,Windows上可创建的线程数量可能更少。基于线程模型的服务器总要受限于这个线程数量的限制。

JVM中可以生成的最大数量由JVM的堆内存大小、Thread的Stack内存大小、系统最大可创建的线程数量(Java线程的实现是基于底层系统的线程机制来实现的,Windows下_beginthreadex,Linux下pthread_create)三个方面影响。具体数量可以根据Java进程可以访问的最大内存(32位系统上一般2G)、堆内存、Thread的Stack内存来估算。

序:

在64位Linux系统(CentOS6,3G内存)下测试,发现还有一个参数是会限制线程数量:maxuserprocess(可通过ulimit–a查看,默认值1024,通过ulimit–u可以修改此值),这个值在上面的32位Ubuntu测试环境下并无限制。

将threads-max,pid_max,maxuserprocess,这三个参数值都修改成100000,-Xms,-Xmx尽量小(128m,64m),-Xss尽量小(64位下最小104k,可取值128k)。事先预测在这样的测试环境下,线程数量就只会受限于测试环境的内存大小(3G),可是实际的测试结果是线程数量在达到32K(32768,创建的数量最多的时候大概是33000左右)左右时JVM是抛出警告:Attempttoallocatestackguardpagesfailed,然后出现OutOfMemoryError无法创建本地线程。查看内存后发现还有很多空闲,所以应该不是内存容量的原因。Google此警告无果,暂时不知什么原因,有待进一步研究。

序2:

今天无意中发现文章[7],马上试了下,果然这个因素会影响线程创建数量,按文中描述把/proc/sys/vm/max_map_count的数量翻倍,从65536变为131072,创建的线程总数量达到65000+,电脑基本要卡死(3G内存)…简单查了下这个参数的作用,在[8]中的描述如下:

“Thisfilecontainsthemaximumnumberofmemorymapareasaprocessmayhave.Memorymapareasareusedasaside-effectofcallingmalloc,directlybymmapandmprotect,andalsowhenloadingsharedlibraries.

Whilemostapplicationsneedlessthanathousandmaps,certainprograms,particularlymallocdebuggers,mayconsumelotsofthem,e.g.,uptooneortwomapsperallocation.

Thedefaultvalueis65536.”

OK,这个问题总算完满解决,最后总结下影响Java线程数量的因素:

Java虚拟机本身:-Xms,-Xmx,-Xss;

系统限制:

/proc/sys/kernel/pid_max,

/proc/sys/kernel/thread-max,

max_user_process(ulimit-u),

/proc/sys/vm/max_map_count。

总结

以上就是本文关于jvm支持最大线程数简单测试的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。

(0)

相关推荐

  • JVM 方法调用之静态分派(详解)

    分派(Dispatch)可能是静态也可能是动态的,根据分派依据的宗量数可分为单分派和多分派.这两种分派方式的两两组合就构成了静态单分派,静态多分派,动态单分派,动态多分派这4种组合.本章讲静态分派. 1.静态分派 所有依赖静态类型来定位方法执行版本的分派动作称为静态分派.静态分派的典型应用是方法重载.静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的. 那么什么是静态类型(static type)呢? Super object = new Sub(); 像上面的语句,Sup

  • JVM之参数分配(全面讲解)

    一.堆参数设置 -XX:+PrintGC 使用这个参数,虚拟机启动后,只要遇到GC就会打印日志 -XX:+UseSerialGC 配置串行回收器 -XX:+PrintGCDetails 可以查看详细信息,包括各个区的情况 -Xms:设置Java程序启动时初始化堆大小 -Xmx:设置Java程序能获得最大的堆大小 -Xmx20m -Xms5m -XX:+PrintCommandLineFlags:可以将隐式或者显示传给虚拟机的参数输出 在实际工作中,我们可以直接将初始的堆大小与最大堆大小设置相等,

  • 浅谈Java堆外内存之突破JVM枷锁

    对于有Java开发经验的朋友都知道,Java中不需要手动的申请和释放内存,JVM会自动进行垃圾回收:而使用的内存是由JVM控制的. 那么,什么时机会进行垃圾回收,如何避免过度频繁的垃圾回收?如果JVM给的内存不够用,怎么办? 此时,堆外内存登场!利用堆外内存,不仅可以随意操控内存,还能提高网络交互的速度. 背景1:JVM内存的分配 对于JVM的内存规则,应该是老生常谈的东西了,这里我就简单的说下: 新生代:一般来说新创建的对象都分配在这里. 年老代:经过几次垃圾回收,新生代的对象就会放在年老代里

  • Java 虚拟机(JVM)之基本概念详解

    1.类加载子系统:负责从文件系统或者网络中加载Class信息,加载的信息存放在一块称之为方法区的内存空间. 2.方法区:就是存放类信息.常量信息.常量池信息.包括字符串字面量和数字常量等.方法区是辅助堆栈的块永久区,解决堆栈信息的产生,是先决条件. 3.Java堆:再java虚拟机启动的时候建立Java堆,它是java程序最主要的内存工作区域,几乎所有的对象实例都存放到Java堆中,堆空间是所有线程共享的.堆解决的是数据存储问题,即数据怎么放.放在哪儿. 4.直接内存:Java的NIO库允许Ja

  • JVM 心得分享(加载 链接 初始化)

    基本概念:类加载的过程大致分为三个阶段 1.加载阶段:本阶段主要把class的二进制代码加载进入JVM,并且进行常量池(类名,方法名,字段名),方法区(二进制字节码),栈(本地方法栈结构),堆(java.lang.class对象)的设置. 有三个加载类:Bootstrap ClassLoader,加载jre/lib/下的类: Extension ClassLoader:加载jre/lib/ext下的类: ApplicationClassLoader:加载classpath下的类(应用程序自己开发

  • Java虚拟机JVM优化实战的过程全记录

    前言 Java虚拟机是运行所有Java程序的抽象计算机,是Java语言的运行环境,它是Java 最具吸引力的特性之一.Java虚拟机是通过在实际的计算机上仿真模拟各种计算机功能模拟来实现的,通过Java虚拟机,您只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行. 最近在看JVM群里有人发了一个GC情况,让人帮忙看优化的,于是我也凑热闹发了出来想让群里的大神们指导优化一下,以下是优化过程记录. 一开始我贴了下面的两张图 jstat看GC记录

  • 详谈jvm--Java中init和clinit的区别

    init和clinit区别 ①init和clinit方法执行时机不同 init是对象构造器方法,也就是说在程序执行 new 一个对象调用该对象类的 constructor 方法时才会执行init方法,而clinit是类构造器方法,也就是在jvm进行类加载-–验证--解析-–初始化,中的初始化阶段jvm会调用clinit方法. ②init和clinit方法执行目的不同 init is the (or one of the) constructor(s) for the instance, and

  • JVM 方法调用之动态分派(详解)

    1. 动态分派 一个体现是重写(override).下面的代码,运行结果很明显. public class App { public static void main(String[] args) { Super object = new Sub(); object.f(); } } class Super { public void f() { System.out.println("super : f()"); } public void f(int i) { System.out

  • jvm支持最大线程数简单测试

    最近想测试下Openfire下的最大并发数,需要开大量线程来模拟客户端.对于一个JVM实例到底能开多少个线程一直心存疑惑,所以打算实际测试下,简单google了把,找到影响线程数量的因素有下面几个: -Xms intial java heap size -Xmx maximum java heap size -Xss the stack size for each thread 系统限制 系统最大可开线程数 测试程序如下: Java代码 : import java.util.concurrent

  • python编程测试电脑开启最大线程数实例代码

    本文实例代码主要实现python编程测试电脑开启最大线程数,具体实现代码如下. #!/usr/bin/env python #coding=gbk import threading import time, random, sys class Counter: def __init__(self): self.lock = threading.Lock() self.value = 0 def increment(self): self.lock.acquire() self.value = v

  • springboot tomcat最大线程数与最大连接数解析

    springboot tomcat最大线程数与最大连接数 首先看看springboot内置的tomcat,该如何配置这两个参数 # 在配置文件中添加如下内容 # tomcat最大线程数,默认为200 server.tomcat.max-threads=200 # tomcat最大连接数,默认为10000(网上的说法) server.tomcat.max-connections=300 如何理解上面两个参数 为了方便理解,我这里使用了springboot编写了一个简单了的服务,包含一个模拟登录的接

  • java线程池:获取运行线程数并控制线程启动速度的方法

    在java里, 我们可以使用Executors.newFixedThreadPool 来创建线程池, 然后就可以不停的创建新任务,并用线程池来执行了. 在提交任务时,如果线程池已经被占满,任务会进到一个队列里等待执行. 这种机制在一些特定情况下会有些问题.今天我就遇到一种情况:创建线程比线程执行的速度要快的多,而且单个线程占用的内存又多,所以很快内存就爆了. 想了一个办法,就是在提交任务之前,先检查目前正在执行的线程数目,只有没把线程池占满的时候在去提交任务. 代码很简单: int thread

  • 深入探讨linux下进程的最大线程数、进程最大数、进程打开的文件数

    =====最大线程数====linux 系统中单个进程的最大线程数有其最大的限制 PTHREAD_THREADS_MAX这个限制可以在 /usr/include/bits/local_lim.h 中查看对 linuxthreads 这个值一般是 1024,对于 nptl 则没有硬性的限制,仅仅受限于系统的资源这个系统的资源主要就是线程的 stack 所占用的内存,用 ulimit -s 可以查看默认的线程栈大小,一般情况下,这个值是 8M可以写一段简单的代码验证最多可以创建多少个线程 复制代码

  • python多线程semaphore实现线程数控制的示例

    前面写过一篇关于python多线程的实现的文章, 但是效果不是最佳的,写法也不是很好.通过网上学习,也了解到了semaphore这个东西. 百度给的解释:Semaphore是一种在多线程环境下使用的设施,该设施负责协调各个线程,以保证它们能够正确.合理的使用公共资源的设施,也是操作系统中用于控制进程同步互斥的量. 一个有趣的例子:假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在

  • 浅谈一下python线程池简单应用

    一.线程池简介 传统多线程方案会使用“即时创建,即时销毁”的策略.尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务时执行时间较短,而且执行次数及其频繁,那么服务器将处于不停的创建线程,销毁线程的状态. 一个线程的运行时间可以分为三部分:线程的启动时间.线程体的运行时间和线程的销毁时间. 在多线程处理的情景中,如果线程不能被重用,就意味着每次线程运行都要经过启动.销毁和运行3个过程.这必然会增加系统相应的时间,减低了效率. 线程池在系统启动时即创建大量空闲的线程,程序只要

  • AJAX简单测试代码实例

    本文实例讲述了AJAX简单测试代码.分享给大家供大家参考.具体如下: 客户端:代码如下:(AJAX_test.html ) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/x

  • PHP机器学习库php-ml的简单测试和使用方法

    php-ml是一个使用PHP编写的机器学习库.虽然我们知道,python或者是C++提供了更多机器学习的库,但实际上,他们大多都略显复杂,配置起来让很多新手感到绝望. php-ml这个机器学习库虽然没有特别高大上的算法,但其具有最基本的机器学习.分类等算法,我们的小公司做一些简单的数据分析.预测等等都是够用的.我们的项目中,追求的应该是性价比,而不是过分的效率和精度.一些算法和库看上去非常厉害,但如果我们考虑快速上线,而我们的技术人员没有机器学习方面的经验,那么复杂的代码和配置反而会拖累我们的项

  • python 统计代码行数简单实例

     python 统计代码行数简单实例 送测的时候,发现需要统计代码行数 于是写了个小程序统计自己的代码的行数. #calclate_code_lines.py import os def afileline(f_path): res = 0 f = open(f_path) for lines in f: if lines.split(): res += 1 return res if __name__=='__main__': host = 'E:'+os.sep+'develop'+os.s

随机推荐