如何测试java支持的xp最大支持多少内存内存

Java堆外内存的使用 - ImportNew
| 标签: ,
最近经常有人问我在Java中使用堆外(off heap)内存的好处与用途何在。我想其他面临几样选择的人应该也会对这个答案感兴趣吧。
堆外内存其实并无特别之处。线程栈,应用程序代码,NIO缓存用的都是堆外内存。事实上在C或者C++中,你只能使用未托管内存,因为它们默认是没有托管堆(managed heap)的。在Java中使用托管内存或者“堆”内存是这门语言的一个特性。注意:Java并非唯一这么做的语言。
new Object() vs 对象池 vs 堆外内存
new Object()
在Java 5.0以前,对象池一度非常流行。那个时候创建对象的开销是非常昂贵的。然而,从Java 5.0以后,对象创建及垃圾回收已经变得非常廉价了,开发人员发现性能得到了提升后,便简化了代码,废弃了对象池,需要的时候就去创建新的对象就好了。在Java 5.0以前,几乎所有对象,包括对象池本身,都通过对象池来提升性能,而在5.0以后,只有那些特别昂贵的对象才有必要池化了,比方说线程,Socket,以及数据库连接。
在低时延领域它仍是有一定的用武之处的,由于可变对象的循环使用减轻了CPU缓存的压力,进而使得性能得到了提升。这些对象的生命周期和结构都必须尽可能简单,但这么做之后你会发现系统性能及抖动都会得到大幅度的改善。
还有一个领域也比较适合使用对象池,譬如需要加载海量数据且其中包含许多冗余对象时。使用对象池能显著减少内存的使用量以及需要GC的对象数,进而换来更短的GC时间以及更高的吞吐量。
这类对象池通常都会设计得比较轻量级,而非简单地使用一个同步的HashMap,因此它们仍是有存在的价值的。
拿类来作一个例子。你可以将一个包含你想要的文本的可重复使用的可变StringBuilder作为参数传给它,它会返回你一个匹配的字符串。直接传递String对象的效率会很低,因为你已经把这个对象创建出来了。StringBuilder则是可以重复使用的。
注意:这个结构有一个很有意思的特性就是它不需要额外的线程安全的机制,比方说volatile或者synchronized,仅需Java所保障的最低限度的线程安全就足够了。你能正确地访问到String内部的final字段,顶多就是读到了不一致的引用而已。
public class StringInterner {
private final String[]
public StringInterner(int capacity) {
int n = Maths.nextPower2(capacity, 128);
interner = new String[n];
mask = n - 1;
private static boolean isEqual(@Nullable CharSequence s, @NotNull CharSequence cs) {
if (s == null)
if (s.length() != cs.length())
for (int i = 0; i & cs.length(); i++)
if (s.charAt(i) != cs.charAt(i))
public String intern(@NotNull CharSequence cs) {
long hash = 0;
for (int i = 0; i & cs.length(); i++)
hash = 57 * hash + cs.charAt(i);
int h = (int) Maths.hash(hash) &
String s = interner[h];
if (isEqual(s, cs))
String s2 = cs.toString();
return interner[h] = s2;
堆外内存的使用
使用堆外内存与对象池都能减少GC的暂停时间,这是它们唯一的共同点。生命周期短的可变对象,创建开销大,或者生命周期虽长但存在冗余的可变对象都比较适合使用对象池。生命周期适中,或者复杂的对象则比较适合由GC来进行处理。然而,中长生命周期的可变对象就比较棘手了,堆外内存则正是它们的菜。
堆外内存的好处是:
可以扩展至更大的内存空间。比如超过1TB甚至比主存还大的空间。
理论上能减少GC暂停时间。
可以在进程间共享,减少JVM间的对象复制,使得JVM的分割部署更容易实现。
它的持久化存储可以支持快速重启,同时还能够在测试环境中重现生产数据。
站在系统设计的角度来看,使用堆外内存可以为你的设计提供更多可能。最重要的提升并不在于性能,而是决定性的。
堆外内存及测试
高性能计算领域最大的一个难点在于重现那些隐蔽的BUG,并证实问题已经得到修复。通过将输入事件及数据以持久化的形式存储到堆外内存中,你可以将你的关键系统变成一系列的复杂状态机。(简单的情况下只有一个状态机)。这样的话在测试环境便能够复现出生产环境出现的行为及性能问题了。
许多投行都通过这项技术来可靠地重现当天系统对某个事件的响应,并分析出该事件之所以这么处理的原因。更为重要的是,你能够立即证明线上的故障已经得到了解决,而不是发现一个问题后,寄希望于它就是引发线上故障的根源。确定性的行为还伴随着确定性的性能。
你可以在测试环境中按照真实的时间来回放事件,由此得到的时延分布也必定是生产环境中所出现的。由于硬件的不同,一些系统的抖动可能难以复现,不过这在数据分析的角度而言已经相当接近真实的情况了。为了避免出现花一整天的时间来回话前一天的数据的情况,你还可以增加一个阈值,比方说,如果两个事件的间隔超过10ms的话你可以就只等待10ms。这样你能够在一个小时内根据实际的时间来回放出一天的事件,来检查下你的改动是否对时延分布有所改善。
这样做是否就损失了“一次编译,处处执行”的好处了?
一定程度上来讲是这样的,但其实的影响比你想像的要小得多。越接近处理器,你就更依赖于处理器或者操作系统的行为。所幸的是,绝大多数系统使用的都是AMD/Intel的CPU,甚至是ARM处理器在底层上也越来越与这两家兼容了。操作系统之间也存在差别,因此相对于Windows而言,这项技术更适合在Linux系统上使用。如果你是在Mac OS X或者Windows上开发,然后生产环境是部署在Linux上的话,就一点问题都没有了。我们在Higher Frequency Trading中也是这么做的。
使用堆外内存会引入什么新的问题
天下没有免费的午餐,堆外内存也不例外。最大的问题在于你的数据结构变得有些别扭。要么就是需要一个简单的数据结构以便于直接映射到堆外内存,要么就使用复杂的数据结构并序列化及反序列化到内存中。很明显使用序列化的话会比较头疼且存在性能瓶颈。使用序列化比使用堆对象的性能还差。
在金融领域,许多高频率的数据都是扁平的简单结构,全部由基础类型组成,非常适合映射到堆外内存。然而,并非所有的应用程序都是这样的,可能会有一些嵌套得很深的数据结构,比如说图,你还不得不将这些对象缓存在堆上。
另外一个问题就是JVM会制约到你对操作系统的使用。你不用再担心JVM会给系统造成过重的负载。使用堆外内存后,某些限制已经不复存在了,你可以使用比主存还大的数据结构,不过如果你这么做的话又得考虑一下使用的是什么磁盘子系统了。比如说,你肯定不会希望分页到一块只有80 IOPS(Input/Ouput Operations per Second,每秒的IO操作)的HDD硬盘上,最好是IOPS能到80,000的SSD硬盘,当然了,1000x的话更好。
OpenHFT能做些什么?
OpenHFT包含许多类库,它们向你屏蔽了使用本地内存来存储数据的细节。这些数据结构都是持久化的,使用它们不会产生垃圾或者只有很少。使用了它的应用程序可以运行一整天也没有一次Minor GC.
——持久化的事件队列。支持同一台机器上多个JVM的并发写,以及多台机器间的并发读。微秒级的延迟,并能持续保持每秒上百万消息的吞吐量。
——kv表的本地或持久化存储。它能在同一台机器的不同JVM间共享,数据是通过UDP或者TCP来复制的,并通过TCP来进行远程访问。微秒级的延迟,单台机器能保持每秒百万级的读写操作。
——将关键线程绑定到独立的CPU核或者逻辑CPU上,以减少系统抖动。抖动可以减小到原来的千分之一。
使用哪个API?
如果你需要记录每个事件的话 ——& Chronicle Queue
如果你只需要某个唯一主键最近的一条结果 ——& Chronicle Map
如果你更关心那20微秒的抖动的话 ——& Thread Affinity
堆外内存是把双刃剑。它的价值你已经看到了,可以和别的实现可伸缩性的方案进行下比较。与在堆缓存或者消息队列,甚至是进程外的数据库中进行分区/分片相比,使用堆外内存要更为简单高效。不仅如此,以前用来提升性能的某些技巧也已经不再需要了。比如说,堆外内存可以支持操作系统的同步写,就不再需要异步去执行了,那样还会面临数据丢失的风险。不过最大的好处应该就是启动时间了,生产环境下的系统的重启速度会大大缩短,映射1 TB的数据只需要10毫秒,同时你还能在测试环境按生产环境的顺序复现每一个事件,以还原线上现场。通过它你可以建立起一个可靠的质量体系。
,受益匪浅~!
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:@
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2016 ImportNew博客访问: 463613
博文数量: 133
博客积分: 7001
博客等级: 少将
技术积分: 1320
注册时间:
APP发帖 享双倍积分
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Java
传说JVM是使用的最大内存一般Windows下M左右,Linux下最大能到2600M。 可以设置的最大JVM内存和JVM版本以及操作系统版本有关,但是一直都不知道我机子的内存支持到底是多少,今天闲来无事,小测一把:
D:\eclipse\workspace\download>java -Xmx1024M -versionjava version "1.5.0_06"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
D:\eclipse\workspace\download>java -Xmx2600M -versionError occurred during initialization of VMCould not reserve enough space for object heapCould not create the Java virtual machine.
D:\eclipse\workspace\download>java -Xmx1500M -versionError occurred during initialization of VMCould not reserve enough space for object heapCould not create the Java virtual machine.
D:\eclipse\workspace\download>java -Xmx1200M -versionjava version "1.5.0_06"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
D:\eclipse\workspace\download>java -Xmx1300M -versionjava version "1.5.0_06"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
D:\eclipse\workspace\download>java -Xmx1400M -versionjava version "1.5.0_06"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
D:\eclipse\workspace\download>java -Xmx1500M -versionError occurred during initialization of VMCould not reserve enough space for object heapCould not create the Java virtual machine.
D:\eclipse\workspace\download>java -Xmx1499M -versionError occurred during initialization of VMCould not reserve enough space for object heapCould not create the Java virtual machine.
D:\eclipse\workspace\download>java -Xmx1490M -versionError occurred during initialization of VMCould not reserve enough space for object heapCould not create the Java virtual machine.
D:\eclipse\workspace\download>java -Xmx1450M -versionError occurred during initialization of VMCould not reserve enough space for object heapCould not create the Java virtual machine.
D:\eclipse\workspace\download>java -Xmx1430M -versionjava version "1.5.0_06"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
D:\eclipse\workspace\download>java -Xmx1440M -versionjava version "1.5.0_06"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
D:\eclipse\workspace\download>java -Xmx1449M -versionError occurred during initialization of VMCould not reserve enough space for object heapCould not create the Java virtual machine.
D:\eclipse\workspace\download>java -Xmx1445M -versionError occurred during initialization of VMCould not reserve enough space for object heapCould not create the Java virtual machine.
D:\eclipse\workspace\download>java -Xmx1443M -versionjava version "1.5.0_06"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
D:\eclipse\workspace\download>java -Xmx1444M -versionjava version "1.5.0_06"Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
哈哈哈,最终结果java -Xmx1444M -version 感觉还是不错地!
阅读(2188) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。zhouanyafu 的BLOG
用户名:zhouanyafu
文章数:30
访问量:6824
注册日期:
阅读量:5863
阅读量:12276
阅读量:357325
阅读量:1053958
51CTO推荐博文
JDK自带的JAVA性能分析工具。它已经在你的JDK bin目录里了,只要你使用的是JDK1.6 Update7之后的版本。点击一下jvisualvm.exe图标它就可以运行了。这里是VisualVM 的官方网站:https://visualvm.dev.java.net,资料很全,同时提供VisualVM最近版本下载。安装只要安装JDK即可,运行jvisualvm.exe ,选择【工具】――【插件】――【可用插件】?2使用2.1.远程机器设置要从远程应用程序中检索数据,需要在远程 JVM 上运行 jstatd 实用程序。即要进行以下操作:1)在jdk 安装目录的bin目录下新建文件jstatd.all.policy,文件内容为: & grant codebase "file:${java.home}/../lib/tools.jar" { permission java.security.AllP};2)再新建文件jstatd.sh ,文件内容为:./jstatd -J-Djava.security.policy=jstatd.all.policy3)启动jstat : nohup jstatd.sh & (默认启动端口为1099)4)配置resin.conf,把以下注释打开: & &&!-- no use args & & &&jvm-arg&-Xdebug&/jvm-arg& & & &&jvm-arg&-Dcom.sun.management.jmxremote&/jvm-arg&2.2.添加远程监控机器2.3.配置Jconsole1)在应用的resin配置文件中加配置:&jvm-arg&-Dcom.sun.management.jmxremote&/jvm-arg&&jvm-arg&-Dcom.sun.management.jmxremote.port=9009&/jvm-arg&&jvm-arg&-Dcom.sun.management.jmxremote.ssl=false&/jvm-arg&&jvm-arg&-Dcom.sun.management.jmxremote.authenticate=false&/jvm-arg&2)选择Tools菜单里的Plugins菜单,点击 'VisualVM-JConsole' 然后点击'Install' 按钮3)安装完毕后重新启动VisualVm4)配置JConsole页签,点击'JConsole Plugins'按钮5)点击'Add JAR/Folder'按钮,6)添加JDK_HOME/demo/management/JTop/JTop.jar7)重新打开监控页面,可以看到JConsole正常工作2.4.远程监控cpu使用情况点采样器栏:点击cpu,观察到cpu使用状况,点击snapshot,采取结果,可以选择查看方法、类或包的cpu使用情况,使用650) this.width=650;" src="/e/u/themes/default/images/spacer.gif" style="background:url(&/e/u/themes/default/images/word.gif&) no-border:1px solid #" height="23" width="26" alt="spacer.gif" />工具可以查找想要查看的方法、类或包:2.5.GC监控1)选择要监控的pid,查看GC情况如果Old区满了,每次回收都很少或者回收不了,说明GC有问题。2.6.远程监控内存泄露、解决内存溢出问题1)内存泄露、溢出的异同同:都会导致应用程序运行出现问题,性能下降或挂起。异:v内存泄露是导致内存溢出的原因之一;内存泄露积累起来将导致内存溢出。v内存泄露可以通过完善代码来避免;内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。2)监测内存泄漏?内存泄漏是指程序中间动态分配了内存,但在程序结束时没有释放这部分内存,从而造成那部分内存不可用的情况,重启计算机可以解决,但也有可能再次发生内存泄露,内存泄露和硬件没有关系,它是由软件设计缺陷引起的。 &?内存泄漏可以分为4类: a. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。 b.偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。 c.一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。d.隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。3)Heap dump 分析每隔一段时间给所检测的应用做一次:(或者在响应应用pid上鼠标右键)弹出以下提示框:在应用服务器将此文件下载到所在的机器上,打开此文件,如下面三图所示:对比上面三个截图,发现似乎有个东西在急速飙升,仔细一看是这个对象:org.eclipse.swt.graphics.Image 在第一章图中这个还没排的上,第二次dump已经上升到5181个,第三次就是7845个了。涨速相当快,而且和任务管理器里面看到的GDI数量增涨一致,就是它了。问题到这儿就比较清楚了,回到代码里面仔细一看可以发现,是某个地方反复的用图片来创建Image对象导致的,改掉以后搞定问题。到这里其实我想说的是,Java使用起来其实要比C++更容易导致内存泄漏。对于C++来说,每一个申请的对象都必须明确释放,任何没有释放的对象都会导致memleak,这是不可饶恕的,而且这类问题已经有很多工具和方法来解决。但是到了Java里面情况就不同了,对于Java程序员来说对象都是不需要也无法主动销毁的,所以一般的思路是:随用随new,用完即丢。很多对象具体的生命周期可能连写代码的人自己也不清楚,或者不需要清楚,只知道某个时刻垃圾收集器会去做的,不用管。但很可能某个对象在“用完即丢”的时候在另一个不容易发现的地方被保存了一个引用,那么这个对象就永远不会被回收。更加糟糕的是整个程序从设计之初就没有考虑过对象回收的问题,对于C++程序员来说memleak必然是一个设计错误,但是对Java程序员来说这只是一个疏忽,而且似乎没有什么好的办法来避免。今天看到的这个问题是因为GDI泄漏会造成严重后果才被重视,但如果仅仅是造成内存泄漏,那这个程序可能得连续跑上个十天半个月才会发现问题。最后就是,对于c++,错误的代码在测试阶段就可以快速的侦测出哪怕一个byte的memleak并加以改正,但是对于java程序,理论上没有哪个工具能够知道是不是有泄漏,因为除了作者自己以外没有人能够知道一个被引用的对象是不是应该被销毁,只有通过大量的,长期的压力测试才能发现问题,这是很危险的一件事情。4)解决内存溢出问题1、java.lang.OutOfMemoryError: PermGen space JVM管理两种类型的内存,堆和非堆。堆是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。如上图所示,PermGen在程序运行一段时间后超出了我们指定的128MB,通过Classes视图看到,Java在运行的同时加载了大量的类到内存中。PermGen会存储Jar或者Class的描述信息;所以在class大量增加的同时PermGen超出了我们指定的范围。为了让应用稳定,我们需要探寻新的PermGen范围。检测时段时候后(如下图)发现PermGen在145MB左右稳定,那么我们就得到了稳定的新参数;这样PermGen内存溢出的问题得到解决。2、java.lang.OutOfMemoryError: Java heap space 第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。 注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。垃圾回收GC的角色,JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收:一个是当应用程序线程空闲;另一个是java内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。根据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。显示调用System.GC()只能建议JVM需要在内存中对垃圾对象进行回收,但不是必须马上回收。一个是并不能解决内存资源耗空的局面,另外也会增加GC的消耗。2.7.如何避免内存泄漏、溢出1)尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。2) 程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer。 因为每一个String对象都会独立占用内存一块区域,如:1.String str = "aaa"; & &2.String str2 = "bbb"; & &3.String str3 = str + str2; & &4.// 假如执行此次之后str , str2再不被调用,那么它们就会在内存中等待GC回收; & &5.// 假如程序中存在过多的类似情况就会出现内存错误; & 3) 尽量少用静态变量。 因为静态变量是全局的,GC不会回收。4) 避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作。 JVM会突然需要大量内存,这时会触发GC优化系统内存环境; 一个案例如下: 1.// 使用jspsmartUpload作文件上传,运行过程中经常出现java.outofMemoryError的错误, & &2.// 检查之后发现问题:组件里的代码 & &3.m_totalBytes = m_request.getContentLength(); & &4.m_binArray = new byte[m_totalBytes]; & &5.// totalBytes这个变量得到的数极大,导致该数组分配了很多内存空间,而且该数组不能及时释放。 & &6.// 解决办法只能换一种更合适的办法,至少是不会引发outofMemoryError的方式解决。 & &7.// 参考:http://bbs./blog/more.asp?name=hongrui&id=3747 & 5) 尽量运用对象池技术以提高系统性能。 生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。6) 不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。 可以适当的使用hashtable,vector 创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃。7) 优化配置。a.设置-Xms、-Xmx相等;b.设置NewSize、MaxNewSize相等;c.设置Heap size, PermGen space: 本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)visionsky 的BLOG
用户名:visionsky
文章数:225
评论数:144
访问量:1139856
注册日期:
阅读量:5863
阅读量:12276
阅读量:357325
阅读量:1053958
51CTO推荐博文
&常见配置举例&
堆大小设置
JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制.32位系统 下,一般限制在1.5G~2G;64为操作系统对内存无限制.我在Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最大可设置为1478m.
典型设置:&
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
-Xmx3550m:设置JVM最大可用内存为3550M.
-Xms3550m:设置JVM促使内存为3550m.此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存.
-Xmn2g:设置年轻代大小为2G.整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8.
-Xss128k:设置每个线程的堆栈大小.JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在左右.
java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代).设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值.设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m.
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄.如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概论.
回收器选择
JVM给了三种选择:串行收集器,并行收集器,并发收集器,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器.默认 情况下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数.JDK5.0以后,JVM会根据当前系统配置进行判断.&
吞吐量优先的并行收集器
如上文所述,并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等.
典型配置:&
java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
-XX:+UseParallelGC:选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收.此值最好配置与处理器数目相等.
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集.JDK6.0支持对年老代并行收集.
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值.
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy
-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开.
响应时间优先的并发收集器
如上文所述,并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间.适用于应用服务器,电信领域等.
典型配置:&
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:+UseConcMarkSweepGC:设置年老代为并发收集.测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代大小最好用-Xmn设置.
-XX:+UseParNewGC:设置年轻代为并行收集.可与CMS收集同时使用.JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值.&
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生&碎片&,使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理.
-XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩.可能会影响性能,但是可以消除碎片
JVM提供了大量命令行参数,打印信息,供调试使用.主要有以下一些:&
-XX:+PrintGC
输出形式:[GC 118250K-&0112K), 0.0094143 secs]&
[Full GC 121376K-&1K), 0.0650971 secs]
-XX:+PrintGCDetails
输出形式:[GC [DefNew: 8614K-&781K(9088K), 0.0123035 secs] 118250K-&0112K), 0.0124633 secs]&
[GC [DefNew: 8614K-&K), 0.0000665 secs][Tenured: 112761K-&1K), 0.0433488 secs] 121376K-&1K), 0.0436268 secs]
-XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可与上面两个混合使用
输出形式:11.851: [GC 98328K-&9K), 0.0082960 secs]
-XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中断的执行时间.可与上面混合使用
输出形式:Application time: 0.5291524 seconds
-XX:+PrintGCApplicationStoppedTime:打印垃圾回收期间程序暂停的时间.可与上面混合使用
输出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
34.702: [GC {Heap before gc invocations=7:
def new generation total 55296K, used 52568K [0x1ebddd0000)
eden space 49152K, 99% used [0x1ebdbce430, 0x21bd0000)
from space 6144K, 55% used [0x221d27e10, 0x227d0000)
to space 6144K, 0% used [0x21bdbdd0000)
tenured generation total 69632K, used 2696K [0x227dbdbd0000)
the space 69632K, 3% used [0x227da720f8, 0x22a7bd0000)
compacting perm gen total 8192K, used 2898K [0x26bddabd0000)
the space 8192K, 35% used [0x26bdea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abdb12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3dbx2bx2bfd0000)
34.735: [DefNew: 52568K-&K), 0.0072126 secs] 55264K-&K)Heap after gc invocations=8:
def new generation total 55296K, used 3433K [0x1ebddd0000)
eden space 49152K, 0% used [0x1ebdebdbd0000)
from space 6144K, 55% used [0x21bdf2a5e8, 0x221d0000)
to space 6144K, 0% used [0x221ddd0000)
tenured generation total 69632K, used 3182K [0x227dbdbd0000)
the space 69632K, 4% used [0x227daeb958, 0x22aeba00, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bddabd0000)
the space 8192K, 35% used [0x26bdea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abdb12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3dbx2bx2bfd0000)
, 0.0757599 secs]
-Xloggc:filename:与上面几个配合使用,把相关日志信息记录到文件以便分析.
常见配置汇总&
-Xms:初始堆大小&
-Xmx:最大堆大小&
-XX:NewSize=n:设置年轻代大小&
-XX:NewRatio=n:设置年轻代和年老代的比值.如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4&
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值.注意Survivor区有两个.如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5&
-XX:MaxPermSize=n:设置持久代大小
收集器设置&
-XX:+UseSerialGC:设置串行收集器&
-XX:+UseParallelGC:设置并行收集器&
-XX:+UseParalledlOldGC:设置并行年老代收集器&
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息&
-XX:+PrintGC&
-XX:+PrintGCDetails&
-XX:+PrintGCTimeStamps&
-Xloggc:filename
并行收集器设置&
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数.并行收集线程数.&
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间&
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比.公式为1/(1+n)
并发收集器设置&
-XX:+CMSIncrementalMode:设置为增量模式.适用于单CPU情况.&
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数.并行收集线程数.
年轻代大小选择&
响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择).在此种情况下,年轻代收集发生的频率也是最小的.同时,减少到达年老代的对象.&
吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度.因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用.
年老代大小选择&
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得:&
并发垃圾收集信息&
持久代并发收集次数&
传统GC信息&
花在年轻代和年老代回收上的时间比例
减少年轻代和年老代花费的时间,一般会提高应用的效率
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象.
较小堆引起的碎片问题
因为年老代的并发收集器使用标记,清除算法,所以不会对堆进行压缩.当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象.但是,当堆空 间较小时,运行一段时间以后,就会出现&碎片&,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记,清除方式进行回收.如果 出现&碎片&,可能需要进行如下配置:&
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩.&
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
在同一个工程下,有两个类,这两个类中只有很少的变动,而最关健的FOR却没有一点变动,可是当我分别运行这两个程序的时候却出现一个很严重的问题,一个程序循环的快,一个循环的慢.这到底是怎么回事呢~???苦苦寻找了半天也没有想到是为什么,因为程序改变的部分根不影响我循环的速度,可是结果却是有很大的差别,一个大约是在一分钟这内就可以循环完,可是另一个却需要六七分钟,这根本就不是一个数据理级的麻.两个完全一样的循环,从代码上根本上是看不出有什么问题.不得以求助同事吧,可是同事看了也感觉很诡异,两个人在那订着代码又看了一个多小时,最后同事让我来个干净点的,关机重启.我到也听话,就顺着同事的意思去了,可就在关机的这个时候他突然说是不是内存的问题,我也空然想到了,还真的有可能是内存的问题,因为快的那个在我之前运行程序之前可给过1G的内存啊,而后来的这个我好像是没有设过内存啊,机器起来了,有了这个想法进去看看吧,结果正中要害,果真是慢的那个没有开内存,程序运行时只不过是JVM默认开的内存.我初步分析是因为内存太小,而我的程序所用内存又正好卡在JVM所开内存边上,不至于溢出.当程序运行时就得花费大部分时间去调用GC去,这样就导致了为什么相同的循环出现两种不同的效率~!
顺便把内存使用情况的方法也贴出来:
public static String getMemUsage() {
long free = java.lang.Runtime.getRuntime().freeMemory();
long total = java.lang.Runtime.getRuntime().totalMemory();&
StringBuffer buf = new StringBuffer();
buf.append(&[Mem: used &).append((total-free)&&20)
.append(&M free &).append(free&&20)
.append(&M total &).append(total&&20).append(&M]&);
return buf.toString();
google一下,大概就说JVM是这样来操作内存:
堆(Heap)和非堆(Non-heap)内存
按照官方的说法:&Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚拟机启动时创建的.&&在JVM中堆之外的内存称为非堆内存(Non-heap memory)&.可以看出JVM主要管理两种类型的内存:堆和非堆.简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所以方法区,JVM内部处理或优化所需的内存(如JIT编译后的代码缓存),每个类结构(如运行时常数池,字段和方法数据)以及方法和构造方法的代码都在非堆内存中.
堆内存分配
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4.默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时, JVM会减少堆直到-Xms的最小限制.因此服务器一般设置-Xms,-Xmx相等以避免在每次GC 后调整堆的大小.
非堆内存分配
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4.
JVM内存限制(最大值)
首先JVM内存首先受限于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系.简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是 2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了
JVM内存的调优
1. Heap设定与垃圾回收Java Heap分为3个区,Young,Old和Permanent.Young保存刚实例化的对象.当该区被填满时,GC会将对象移到Old区.Permanent区则负责保存反射对象,本文不讨论该区.JVM的Heap分配可以使用-X参数设定,
初始Heap大小
java heap最大值
young generation的heap大小
JVM有2个GC线程.第一个线程负责回收Heap的Young区.第二个线程在Heap不足时,遍历Heap,将Young 区升级为Older区.Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能.
为什么一些程序频繁发生GC?有如下原因:
l 程序内调用了System.gc()或Runtime.gc().
l 一些中间件软件调用自己的GC方法,此时需要设置参数禁止这些GC.
l Java的Heap太小,一般默认的Heap值都很小.
l 频繁实例化对象,Release对象.此时尽量保存并重用对象,例如使用StringBuffer()和String().
如果你发现每次GC后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态.许多Server端的Java程序每次GC后最好能有65%的剩余空间.经验之谈:
1.Server端JVM最好将-Xms和-Xmx设为相同值.为了优化GC,最好让-Xmn值约等于-Xmx的1/3[2].
2.一个GUI程序最好是每10到20秒间运行一次GC,每次在半秒之内完成[2].
1.增加Heap的大小虽然会降低GC的频率,但也增加了每次GC的时间.并且GC运行时,所有的用户线程将暂停,也就是GC期间,Java应用程序不做任何工作.
2.Heap大小并不决定进程的内存使用量.进程的内存使用量要大于-Xmx定义的值,因为Java为其他任务分配内存,例如每个线程的Stack等.
2.Stack的设定
每个线程都有他自己的Stack.
每个线程的Stack大小
Stack的大小限制着线程的数量.如果Stack过大就好导致内存溢漏.-Xss参数决定Stack大小,例如-Xss1024K.如果Stack太小,也会导致Stack溢漏.
3.硬件环境
硬件环境也影响GC的效率,例如机器的种类,内存,swap空间,和CPU的数量.
如果你的程序需要频繁创建很多transient对象,会导致JVM频繁GC.这种情况你可以增加机器的内存,来减少Swap空间的使用[2].
第一种为单线程GC,也是默认的GC.,该GC适用于单CPU机器.
第二种为Throughput GC,是多线程的GC,适用于多CPU,使用大量线程的程序.第二种GC与第一种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程.-XX:+UseParallelGC参数启动该GC.
第三种为Concurrent Low Pause GC,类似于第一种,适用于多CPU,并要求缩短因GC造成程序停滞的时间.这种GC可以在Old区的回收同时,运行应用程序.-XX:+UseConcMarkSweepGC参数启动该GC.
第四种为Incremental Low Pause GC,适用于要求缩短因GC造成程序停滞的时间.这种GC可以在Young区回收的同时,回收一部分Old区对象.-Xincgc参数启动该GC.
4种GC的具体描述参见[3].
1. JVM Tuning. /resin-3.0/performance/jvm-tuning.xtp#garbage-collection
2. Performance tuning Java: Tuning steps
http://h21007./dspp/tech/tech_TechDocumentDetailPage_IDX/1,.html
3. Tuning Garbage Collection with the 1.4.2 JavaTM Virtual Machine .
/docs/hotspot/gc1.4.2/
了这篇文章
类别:┆阅读(0)┆评论(0)

我要回帖

更多关于 电脑支持最大内存 的文章

 

随机推荐