JVM内存模型以及垃圾回收
http://www.rsky.com.cn/Article/java/201006/11926.html
http://www.360doc.com/content/10/0811/19/61497_45329642.shtml
http://blog.csdn.net/user4570/archive/2009/04/01/4040687.aspx
在linux /unix 下或编辑 httpd.sh, 如下内容:
args='-J-server -Xms200m -Xmx1024m -Xloggc:./log/gc.log -XX:MaxNewSize=256m -XX:MaxPermSize=256m -Djava.awt.headless=true'
说明:
(1)J-server -Xms200m -Xmx1024m 其中,-Xms200m 表示启动时,初时内存大小,-Xmx1024m
最大内存占用大小。
(2)-XX:MaxNewSize=256m -XX:MaxPermSize=256m 表示:内存的永久保存区域的大小
(3)-Djava.awt.headless=true 解决在linux/unix验证码图片不能显示的问题。
而到了resin3.1, 则只需修改resin.conf,如下配置即可
<jvm-arg>-Xmx2048m</jvm-arg>
<jvm-arg>-Xms1024m</jvm-arg>
<jvm-arg>-Xss1m</jvm-arg>
<jvm-arg>-Xdebug</jvm-arg>
<jvm-arg>-Dcom.sun.management.jmxremote</jvm-arg>
/opt/resin-fuxi/bin/httpd.sh 增加 FUXI_XOA参数
FUXI_XOA="-Dxoa.hosts.fuxi.xoa.renren.com=10.3.19.200:8388"
args="-Xms4000M -Xmx4000M -J-server -J-Xss128k -J-XX:ThreadStackSize=128 -XX:MaxPermSize=128M -J-verbosegc -J-XX:+PrintGCDet
ails -J-XX:+UseParallelGC -J-XX:+PrintGCTimeStamps $FUXI_XOA -Djava.library.path=/opt/resin-fuxi/libexec:/opt/j2sdk/lib:/us
r/lib64 -Djmagick.systemclassloader=false"
--------------------------------------------
在近日的测试中发现,无论resin.conf中配置的并发连接数多高,例如2048,resin实例能支持的并发活动线程数,或者说是活动连接数,最高只能去到500多。
linux下使用以下命令查看:ps -eLf |grep |wc -l
// default timeout
private long _timeout = 65000L;
private int _connectionMax = 512;//查找resin所有源码后,发现没有对这个值进行设置
private int _minSpareConnection = 16;
private int _keepaliveMax = -1;
private int _minSpareListen = 5;
private int _maxSpareListen = 10;
这个加大以后能到3000
<thread-pool>
<!-- Maximum number of threads. -->
<thread-max>20480</thread-max>
<!-- Minimum number of spare connection threads. -->
<spare-thread-min>10</spare-thread-min>
</thread-pool>
然后就会报这个错误
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:574)
at com.caucho.util.ThreadPool$ThreadLauncher.startConnection(ThreadPool.java:621)
at com.caucho.util.ThreadPool$ThreadLauncher.run(ThreadPool.java:660)
这个限制可以换64位系统解决:
这个异常问题本质原因是我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。能创建的线程数的具体计算公式如下:
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
MaxProcessMemory 指的是一个进程的最大内存
JVMMemory JVM内存
ReservedOsMemory 保留的操作系统内存
ThreadStackSize 线程栈的大小
在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。
结合上面例子我们来对公式说明一下:
MaxProcessMemory 在32位的 windows下是 2G
JVMMemory eclipse默认启动的程序内存是64M
ReservedOsMemory 一般是150M左右
ThreadStackSize 32位 JDK 1.5默认的stacksize 256K左右
公式如下:
(2*1024*1024-64*1024-150*1024)/256 = 7336
公式计算所得7336,和实践7117基本一致(有偏差是因为ReservedOsMemory不能很精确)
由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生java.lang.OutOfMemoryError: unable to create new native thread。
咦,有点背我们的常理,恩,让我们来验证一下,依旧使用上面的测试程序,加上下面的JVM参数,测试结果如下:
ThreadStackSize JVMMemory 能创建的线程数
默认的256K -Xms64m -Xmx64m i = 7117
默认的256K -Xms32m -Xmx32m i = 7244
-Xss128k -Xms64m -Xmx64m i = ?
完全和公式一致。
三、解决问题:
1, 如果程序中有bug,导致创建大量不需要的线程或者线程没有及时回收,那么必须解决这个bug,修改参数是不能解决问题的。
2, 如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory,JVMMemory,ThreadStackSize这三个因素,来增加能创建的线程数:
a, MaxProcessMemory 使用64位操作系统
b, JVMMemory 减少JVMMemory的分配
c, ThreadStackSize 减小单个线程的栈大小