jvm优化及resin配置优化
- 格式:ppt
- 大小:1.50 MB
- 文档页数:22
JVM性能调优Posted on 2010-06-26 06:48 chen77716阅读(1208) 评论(3) 编辑收藏最近因项目存在内存泄漏,故进行大规模的JVM性能调优,现把经验做一记录。
一、JVM内存模型及垃圾收集算法1.根据Java虚拟机规范,JVM将内存划分为:∙New(年轻代)∙Tenured(年老代)∙永久代(Perm)其中New和Tenured属于堆内存,堆内存会从JVM启动参数(-Xmx:3G)指定的内存中分配,Perm 不属于堆内存,有虚拟机直接分配,但可以通过-XX:PermSize -XX:MaxPermSize等参数调整其大小。
∙年轻代(New):年轻代用来存放JVM刚分配的Java对象∙年老代(Tenured):年轻代中经过垃圾回收没有回收掉的对象将被Copy到年老代∙永久代(Perm):永久代存放Class、Method元信息,其大小跟项目的规模、类、方法的量有关,一般设臵为128M就足够,设臵原则是预留30%的空间。
New又分为几个部分:∙Eden:Eden用来存放JVM刚分配的对象∙Survivor1∙Survivro2:两个Survivor空间一样大,当Eden中的对象经过垃圾回收没有被回收掉时,会在两个Survivor之间来回Copy,当满足某个条件,比如Copy次数,就会被Copy到Tenured。
显然,Survivor只是增加了对象在年轻代中的逗留时间,增加了被垃圾回收的可能性。
2.垃圾回收算法垃圾回收算法可以分为三类,都基于标记-清除(复制)算法:∙Serial算法(单线程)∙并行算法∙并发算法JVM会根据机器的硬件配臵对每个内存代选择适合的回收算法,比如,如果机器多于1个核,会对年轻代选择并行算法,关于选择细节请参考JVM调优文档。
稍微解释下的是,并行算法是用多线程进行垃圾回收,回收期间会暂停程序的执行,而并发算法,也是多线程回收,但期间不停止应用执行。
JVM优化配置OOM这个缩写就是Java程序开发过程中让人最头痛的问题:Out ofMemory。
在很多开发人员的开发过程中,或多或少的都会遇到这类问题,这类问题定位比较困难,往往需要根据经验来判断可能出现问题的代码。
原因主要是两个:对象没有被释放(多种情况引起,往往是比较隐蔽的引用导致被Hold而无法被回收)。
另一种就是真的Memory不够用了,需要增加JVM的Heap来满足应用程序的需求。
最近有同事发的关于解决OOM的问题,让我了解了原来OOM 除了在JVM Heap不够时会发生,在NativeHeap不够的时候也会发生,同时JVM Heap和NativeHeap存在着相互影响和平衡的关系,因此就仔细的去看了关于OOM和JVM配置优化的内容。
OOM在其他语言类似于C,Delphi等等由于内存都是由自己分配和管理,因此内存泄露的问题比较常见,同时也是很头痛的一件事情。
而Java的对象生命周期管理都是JVM来做的,简化了开发人员的非业务逻辑的处理,但是这种自动管理回收机制也是基于一些规则的,而违背了这些规则的时候,就会造成所谓的“Memory Leak”。
OOM(Java Heap)错误提示:ng.OutOfMemoryError。
这类OOM是由于JVM分配的给应用的HeapMemory已经被耗尽,可能是因为应用在高负荷的情况下的却需要很大的内存,因此可以通过修改JVM参数来增加Java HeapMemory(不过也不能无限制增加,后面那种OOM有可能就是因为这个原因而产生)。
另一种情况是因为应用程序使用对象或者资源没有释放,导致内存消耗持续增加,最后出现OOM,这类问题引起的原因往往是应用已不需要的对象还被其他有效对象所引用,那么就无法释放,可能是业务代码逻辑造成的(异常处理不够例如IO等资源),也可能是对于第三方开源项目中资源释放了解不够导致使用以后资源没有释放(例如JDBC的ResultSet等)。
《Java性能调优指南》随着互联网的飞速发展,Java作为一种重要的编程语言,被越来越广泛地应用于各个领域。
但是,Java程序的性能问题也随之出现。
如何调优Java 程序的性能,成为了每个开发人员需要解决的难题。
本文将为大家介绍Java性能调优的指南。
一、JVM参数设置JVM(Java虚拟机)参数设置是Java性能调优的关键。
JVM有众多的参数,不同的参数设置会对Java程序的性能产生不同的影响。
常用的JVM参数设置包括以下几个方面:1. 内存设置内存是Java程序的一大瓶颈。
如果内存设置不合理,会导致Java程序频繁地进行垃圾回收,造成程序的延迟和不稳定。
在设置内存参数时需要注意以下几点:- -Xmx: 最大堆内存,设置合理的最大堆内存大小可以减少JVM的垃圾回收次数,提高程序性能。
- -Xms: 初始堆内存,设置合理的初始堆内存大小可以加快程序启动时间,提高程序性能。
- -XX:NewRatio: 新生代与老年代的比例,如果设置得当,可以减少垃圾回收的次数。
通常新生代的大小为总堆容量的1\/3或1\/4,老年代的大小为总堆容量的2\/3或3\/4。
2. 垃圾回收设置垃圾回收是Java程序中必不可少的一部分。
合理的垃圾回收参数设置可以提高程序性能。
常用的垃圾回收参数设置包括以下几点:- -XX:+UseParallelGC: 使用并行GC,适用于多核CPU。
- -XX:+UseConcMarkSweepGC: 使用CMS GC,适用于大型Web应用程序。
- -XX:+UseG1GC: 使用G1 GC,适用于大内存应用程序。
3. JIT设置JIT(即时编译器)是Java程序中非常重要的一部分。
合理的JIT参数设置可以提高程序的性能。
常用的JIT参数设置包括以下几点:- -XX:+TieredCompilation: 启用分层编译,可以提高程序启动时间和性能。
- -XX:CompileThreshold: JIT编译阈值,设置JIT编译的最小方法调用次数,可以提高程序性能。
Java虚拟机JVM各调优参数说明Java虚拟机(JVM)是Java程序运行的环境,它负责将Java源代码编译为字节码,并在运行时执行这些字节码。
JVM的性能对于Java应用程序的性能至关重要。
为了优化JVM的性能,我们可以通过调整一些参数来改变其行为。
下面是JVM各调优参数的详细说明。
1. -Xms和-Xmx:这两个参数用于设置JVM的初始堆大小和最大堆大小。
初始堆大小表示JVM在启动时申请的内存大小,最大堆大小表示JVM所能申请的最大内存大小。
可以使用以下命令设置初始堆大小为1GB,最大堆大小为2GB:-Xms1g -Xmx2g。
2. -XX:NewSize和-XX:MaxNewSize:这两个参数用于设置新生代的初始大小和最大大小。
新生代是JVM堆的一部分,用于存放新创建的对象。
可以使用以下命令设置新生代的初始大小为256MB,最大大小为512MB:-XX:NewSize=256m -XX:MaxNewSize=512m。
3. -XX:SurvivorRatio:这个参数用于设置新生代中Eden区和Survivor区的比例。
Eden区是新对象的分配区域,Survivor区是用于存放幸存的对象的区域。
可以使用以下命令设置Eden区和Survivor区的比例为8:1:-XX:SurvivorRatio=84. -XX:MaxTenuringThreshold:这个参数用于设置对象在Survivor区中的最大年龄。
当对象在Survivor区中存活的时间超过这个阈值时,它将被晋升到老年代。
可以使用以下命令设置最大年龄为15:-XX:MaxTenuringThreshold=155. -XX:PermSize和-XX:MaxPermSize:这两个参数用于设置永久代的初始大小和最大大小。
永久代用于存放类的元数据、静态变量和常量池等信息。
可以使用以下命令设置永久代的初始大小为128MB,最大大小为256MB:-XX:PermSize=128m -XX:MaxPermSize=256m。
Resin Session AnalysisWritten by Wooce 1. Resin的Reliability和Load balance机制Resin在Web Server中的内嵌模块处理请求的顺序:1)Web Server接收到请求2)内嵌模块(mod_caucho, mod_isapi等)检查是否由Resin处理的请求3)内嵌模块选中一个后台JVM,也就是一个<srun>:a.如果是已有的session, 则选中拥有该session的那一个JVMb.如果是新的请求,则采用轮循策略交由下一个<srun>处理4)内嵌模块通过TCP Socket把请求发给选中的后台JVM5)内嵌模块再通过同一TCP Socket连接接收后台JVM的响应结果.所有的有关内嵌模块和后台JVM均在resin.conf这一配置文件中配置, 使维护变得容易.因为内嵌模块需要决定选用哪一个JVM,所以负载平衡由内嵌模块控制.从JVM的角度看,来自内嵌模块的请求和HTTP请求是同样的,除了编码稍有不同.例如, Resin1.2或以上,同一个JVM可以在同一个端口8080同时作为srun和httpd服务器服务.轮循策略虽然简单, 但它实际上和其他复杂的负载平衡测率一样有效, 并且正由于简单, 它更加健壮和快速.1.1单机最廉价的备份策略. 它在单台机器上运行一个Web Server和两个JVM. 其中一个是主服务JVM, 另一个是后备JVM, 如果主JVM失效, 将启用后备JVM维持Servlet Engine仍然可用. 在resin.conf中的相应配置例子:启动时应该分别单独地启动这两个sun进程. 例如unix下:在NT下:1.2单Web Server, 多JVM当有多台计算机的时候, 可以把负载分担到一台Web Server和多个JVM上, 这比用路由器实现负载平衡较为廉价. 并且采用Resin自己的负载平衡机制,可以保证使同一个session 停留在同一台计算机上.配置举例:各台计算机可以共享使用同一个resin.conf, 但也可以为Web Server和每个JVM分别使用不同的resin.conf.为了确保session停留在固定的机器上, Resin对cookie的编码中加上了主机号标识. 1.3多Web Server和JVM对于大型的服务网站, 一般使用多台计算机, 并且每台计算机都分别运行一个Web Server和一个JVM, 由Router负责把负载分担到不同的机器上.对于这种方法, 由于Router随机地把负载分配到某台机器上, 所以发给某台host的请求的Session不一定是这台Host拥有的.因此需要把任何持久的session维护在一台中央服务器如JDBC数据库上或者采用其他方法使能够由session的id找到拥有该session的机器.即使对于这种Router负载平衡方法, 仍然可以用Resin自己的load balance策略提高可靠性. 对于每一台host上的web server, 都应该首先使用同一台host上运行的JVM进行处理, 但同时可以另一台Host上运行的JVM作为后备.上面例子中host1, host2,host3上的JVM只有当localhost上的JVM失败时才会被启用.另一个例子:1.4多Web Server, 单JVM多个Web Server可以同时使用同一个JVM处理请求. 例如, 我们有一个高速的一般的Web Server和一个采用SSL加密的Web Server的时候, 这两个Web Server可以由同一个JVM 处理请求(虽然如果有一个后备JVM的话会更好), 这简化了引入SSL的开发.2. Resin内部实现distributed sessions的机制2.1 session的backing store的概念和内存中的session的同步更新在Resin设置成load balance over multiple machine的情况, 各台运行web server和JVM 的机器组成一个load balancing pool.为实现load balance over multiple machine下的distributedsession, 必须考虑一个session在被生成后, 在load balancing pool中其他不拥有该session的机器如何访问它, 以及如何同步它们. 在Resin中是通过把session存储到backing store中来解决的, 一个JVM创建了一个新的session后,就把它存储到backing store去, 然后只要保证以下条件:(1)每个内存中有此session的JVM如果更新了此session, 就把更新后的session写到backing store中去, 并且backing store里做到在写某一session的时候不会同时接受读取同一session的请求.(2)每个JVM在读取session的时候,如果它的内存cache中还没有该session, 一定到backing store去读取.(3)某个JVM: Server A在读取session的时候,如果它的内存cache中已有该session, 这时只要满足以下的其中一种情况即可:a. 在(1)中写session到backing store里时保证同时更新了Server A的内存cache中的sessionb. 到backing store中再load出session并以此更新内存cache中的session显然, 满足了以上3个条件, 不同的机器存取同一session的时候就有很好的同步性, 并且亦有较好的性能.在Resin中, backing store可采用3种实现方式: (参看src/com/caucho/server/http/下的SessionStore.java,SessionFileStore.java,SessionJdbcStore.java和SessionRingStore.java)(1)SessionFileStore(这一方式在我所看的Resin2.0.2的代码里实际上还未实现)session的backing store在生成它的Host的文件系统(Resin似乎考虑在将来实现一个在不同的运行JVM的机器之间共享文件的网络文件系统VFS)上.(2)SessionJdbcStore在一台中央服务器上的database作为backing store, 每台Host上生成的session都通过JDBC存储到中央服务器的database中去.(3)SessionRingStore在这种方式中, load balancing pool中所有的运行JVM的机器按host id从小到大(host id 的首字母从’a’到’z’的顺序)组成一个JVM的index号的环, 当环中的某一台Host生成了一个session(session里记录了生成它的JVM的index号)的时候, 就以生成该session的JVM的index号开始, 在环上顺序查找, 只要某一个index的JVM是可用的, 就把session存储到运行该JVM的机器的本地文件系统中, 这样在两台机器上都分别存储了这个session的副本的时候就停止. 明显可看出, 一般情况下(所有JVM都没有crash down)每个session都有两个副本分别存储在生成它的那台机器和环中的下一台机器的文件系统中.Resin采用上述3种方式中的哪种方式来实现distributed session决定于:IF resin.conf中session-config/file-store和其下的directory的tag不为空THEN 采用SessionFileStore;ELSE IF resin.conf中session-config/tcp-store为true THEN 采用SessionRingStore;ELSE IF resin.conf中session-config/jdbc-store不为空THEN 采用SessionJdbcStore;在Resin的实现中,(1)SessionRingStore方式一定能满足上面所说的3个条件, 同步性最好.而对于(2)SessionFileStore和SessionJdbcStore两种方式a. 当resin.conf中session-config/always-load-session为false的时候, 如果一个JVM读入了session在内存cache中, 以后除非timeout再从backing store中reload的情况, 以后有请求都一定从内存cache中读该session, 不能看到其他JVM在此期间对该session 的更新, 这时同步性最差, 但由于不需从backing store中读取, 响应速度最快;b. 当resin.conf中session-config/always-load-session为true的时候, 这时任何请求都会到backing store中读取, 同步性好, 但由于session的内存cache实际上不起作用, 对请求的响应速度最慢.2.2 相关类分析2.2.1 QSession类实现HttpSession接口, 在Resin系统中某个JVM内存中的session就是一个QSession对象, JVM内存cache中的QSession对象需要和backing store中的session保持同步更新.2.2.2 VirtualHost类在一个JVM上处理的所有Servlet application的集合.2.2.3 SrunConnection类维护本JVM到另一个JVM的一个用以交换session的socket连接.2.2.4ServletServer类实现Server接口其他:hostList: ArrayList类型(VirtualHost对象)addHost(String id, RegistryNode node, String appDir)函数:根据(id, node, appDir)新建一个VirtualHost对象并存入HashTable类型成员hosts中.init()函数:初始化invocationCache(LRUCache类型)等内存中的Cache;调用initHosts()函数初始化hosts 等;2.2.5 SessionStore类负责session的访问(读取/存储)操作的基类, SessionFileStore,SessionJdbcStore, SessionRingStore等都是它的子类.2.2.5SessionBacking类封装session存储在file system上的backing path上时的访问操作的接口.2.2.6 SessionManager类管理一个servlet application的所有session重要数据成员和函数:2.2.6SessionRingStore类当以Ring方式的backing store存储distributed sessions时SessionStore类的实现.SessionRingStore.java的void store(QSession session)函数:int sessionIndex = session.getSrunIndex(); //生成该QSession对象的JVM的index号int srunIndex = manager.getSrunIndex(); //执行本函数的JVM的index号int srunCount = manager.getSrunCount(); //Load balancing pool中所有JVM的数目if (sessionIndex < 0)sessionIndex = srunIndex;int index = sessionIndex; //在环中从生成该QSession对象的JVM的index号开始ReadWritePair rws = null;boolean hasSelf = false;int saveCount = 2; //分别存储2个副本到2个JVM的file system中for (int i = srunCount - 1; i >= 0 && saveCount > 0; i--) {//在环上查找一周,并且成功存//储2个副本时就停止if (index == srunIndex) { //环上的当前index号是本机的index号, 令hasSelf为truehasSelf = true; //使在后面的代码段中将会调用StoreSelf()函数存储Session副saveCount--; //本到本机的file system中}else {rws = server.getRecycleConnection(index); //环上当前检查的index号是其他机器,if (rws != null) { //取出可用的socket连接把QSession对象传给index号host让它try { //存储或更新到它的本地file sytem(由RunnerRequest.java处理) saveSession(tempStream, backing.getId(), index, rws);saveCount--;} catch (IOException e) {rws.getReadStream().close();rws.getWriteStream().close();rws = null;}}if (rws == null) {rws = server.getSessionConnection(index);if (rws != null) {try {saveSession(tempStream, backing.getId(), index, rws);saveCount--;} catch (IOException e) {rws.getReadStream().close();rws.getWriteStream().close();rws = null;}}}}index = (index + 1) % srunCount; //取环中的下一个JVM}if (hasSelf) {ReadStream is = tempStream.openRead(true);storeSelf(session, is); //存储session到本地file systemis.close();storeSelf()函数如下:private void storeSelf(QSession session, ReadStream is){SessionBacking backing = session.getBacking();synchronized (backing) { //通过异步synchronized避免多个请求时的写冲突try {Path sessionPath = backing.getPath(); //获得session在本地file system上的存储路径WriteStream os = sessionPath.openWrite();os.writeStream(is);os.close();} catch (IOException e) {if (dbg.canWrite())dbg.log(e);}}boolean load(QSession session)throws Exception{SessionBacking backing = session.getBacking();if (backing == null)return false;int sessionIndex = session.getSrunIndex();int srunIndex = manager.getSrunIndex();int srunCount = manager.getSrunCount();if (sessionIndex < 0)sessionIndex = srunIndex;int updateCount = session.getUpdateCount();/* servers A and B don't need auto-reloading, but server C does.这里server A和server B即指存有session副本的那两个server,当本JVM是server A或server B之一的时候, 显然本JVM的内存cache里的session 肯定是整个load balancing pool中最新的, 所以从这里退出来后回到SessionManager类//的QSession getSession(String key, long now)函数往下执行到else if (sessionStore != null && now > 0 &&(reloadEachRequest || session.needsLoad()))load(session, now);这里session.needsLoad()函数必须返回false, 反之不是server A和server B的情况session.needsLoad()函数就必须返回true以便调用load(session,now)从server A和server B 上获取最新更新的session, 所以在这里的符合条件判断时的代码段内有session.setNeedsLoad(true);语句*/if (srunIndex != sessionIndex &&(sessionIndex + 1) % srunCount != srunIndex) {updateCount = -1;session.setUpdateCount(-1);session.setNeedsLoad(true);}ReadWritePair rws = null;int index = sessionIndex;int loadCount = 2;// Find a live serverfor (int i = srunCount - 1; i >= 0 && loadCount > 0; i--) {try {if (srunIndex != index) {rws = server.getRecycleConnection(index);if (rws != null) {try {if (loadSession(session, index, backing.getId(),rws, updateCount)) {loadCount--;updateCount = session.getUpdateCount();}} catch (IOException e) {rws.getReadStream().close();rws.getWriteStream().close();rws = null;}}if (rws == null) {rws = server.getSessionConnection(index);if (rws != null &&loadSession(session, index, backing.getId(),rws, updateCount)) {updateCount = session.getUpdateCount();loadCount--;}}}else if (loadSelf(session, updateCount)) {if (dbg.canWrite()) {dbg.log("[" + server.getServerId() + "] self-load(" + index + ") " +backing.getId() + " " + backing.getPath());}updateCount = session.getUpdateCount();loadCount--;}} catch (Exception e) {if (dbg.canWrite())dbg.log(e);}if (srunCount > 1)index = (index + 1) % srunCount;return loadCount < 2 && updateCount > 0;}2.3 对Session的处理流程2.3.1 新的请求(需要新生成一个原来在backing store中没有的session)的情况当有新的请求时,1) 执行Request.getSession(boolean create=true) (指调用Request类的getSession(Boolean create)函数, 并传参数create为true,下同) .2) Request.getSession(boolean create)调用AbstractRequest.createSession(boolean create, boolean hasOldSession)函数.3) AbstractRequest.createSession(boolean create, boolean hasOldSession)最后调用SessionManager.createSession(String oldId, long date, int sessionGroup,HttpServletRequest request)创建QSession对象(但只在内存中, 并未存储到backing store)4) 对Request的处理完成, 调用Request.finish().5)Request.finish()调用QSession.finish().6)QSession.Finish()调用SessionStore.Store(QSession Session)完成将session存储到backing store的过程.2.3.2对旧有Session的请求(backing store中存在此id的session)的情况1)执行Request.getSession(Boolean create=false)2)Request.getSession(boolean create)调用AbstractRequest.createSession(boolean create,boolean hasOldSession).3)AbstractRequest.createSession(boolean create, boolean hasOldSession)调用SessionManager.getSession(String key, long now)4)SessionManager.getSession(String key, long now)在内存Cache中查找此QSession对象, 如果需要reload, 还要从backing store中读取QSession对象的更新的值, 然后返回QSession对象.2.3.3非法请求(整个系统中不存在此id的session)的情况在Request类中的boolean isRequestedSessionIdValid()函数即能判断, 它将调用Request.getSession(false)在本JVM的内存cache和backing store中查找此id的session, 如果都找不到则返回false.附AbstractRequest.java的createSession(boolean create, boolean hasOldSession)函数的注解: protected QSession createSession(boolean create, boolean hasOldSession){Application application = getApplication();SessionManager manager = application.getSessionManager();String id = getRequestedSessionId(); //读取请求中发过来的session idlong now = Alarm.getCurrentTime();QSession session;if (id != null && id.length() > 6) {session = manager.getSession(id, now); //从内存cache中读取此id的QSession对象, 没if (session == null) { //有则创建一个}else if (session.isValid()) //成功则返回该QSession对象return session;elseid = null;}if (hasOldSession)id = null;if (! create)return null;// Must accept old ids because different applications in the same// server must share the same cookie//// But, if the session group doesn't match, then create a new// session.session = manager.createSession(id, now, getSessionGroup(), this); //新建QSession对象if (session != null) //注意创建QSession对象和创建一个存储在backing store中//session不是一回事.setHasCookie();if (id != null)return session;if (manager.enableSessionCookies())getResponse().setSessionId(session.getId());return session; //返回新创建的QSession对象}。
JVM虚拟机性能调优调试JVM虚拟机性能调优调试JVM(Java虚拟机)是Java运行环境的重要组成部分,它负责将Java字节码转换为机器码并执行。
然而,在开发和部署Java应用程序时,我们经常会遇到性能瓶颈和调试问题。
本文将介绍如何进行JVM虚拟机性能调优调试,以提高Java应用程序的运行效率。
1. 监控工具的使用监控工具是进行JVM性能调优的重要工具。
JVM自带了一些常用的监控工具,例如JConsole和VisualVM。
它们可以提供关于JVM运行状态的详细信息,包括内存使用情况、线程状态和垃圾回收情况等。
通过监控工具,我们可以及时发现潜在的性能问题,并采取相应的措施进行调优。
2. 垃圾回收调优垃圾回收是JVM自动管理内存的重要机制,但不正确的垃圾回收策略可能会导致性能下降。
调优垃圾回收可以通过调整JVM的参数来实现。
例如,可以通过-Xms和-Xmx参数来调整堆内存的初始大小和最大大小,以避免频繁的垃圾回收。
另外,可以通过调整-XX:NewRatio参数来平衡新生代和老年代的比例,以减少Full GC的次数。
3. 线程管理和调优线程是Java应用程序的重要组成部分,正确地管理和调优线程可以提高应用程序的性能。
首先,应避免创建过多的线程,因为线程的创建和销毁是有开销的。
其次,可以通过调整线程池的大小来优化线程的使用。
合理地设置线程池的核心线程数和最大线程数,可以避免线程过多导致的性能下降和资源浪费。
4. JVM参数调优JVM的参数设置对应用程序的性能有很大的影响。
可以通过调整JVM的参数来优化应用程序的性能。
例如,可以通过调整-XX:MaxPermSize参数来增加永久代的大小,以避免出现PermGen Space的OOM错误。
另外,可以通过调整-XX:MaxHeapFreeRatio参数来控制堆内存的空闲比例,以减少Full GC的次数。
5. 代码优化除了调优JVM的参数和配置,代码优化也是提高应用程序性能的重要手段。
Java中的性能优化有哪些常见方法在 Java 开发中,性能优化是一个至关重要的环节。
随着应用规模的不断扩大和用户需求的日益增长,确保程序能够高效运行、快速响应变得尤为重要。
下面我们就来探讨一下 Java 中的一些常见性能优化方法。
一、算法和数据结构的选择选择合适的算法和数据结构是性能优化的基础。
例如,对于频繁的插入和删除操作,链表可能比数组更合适;对于快速查找操作,哈希表可能比线性搜索更高效。
在实际开发中,需要根据具体的业务需求和数据特点,选择最优的数据结构和算法。
比如,在一个需要快速查找元素是否存在的场景中,如果使用线性搜索,时间复杂度为 O(n),而使用哈希表,平均时间复杂度可以达到O(1)。
这将大大提高程序的执行效率。
二、减少对象创建和销毁在 Java 中,对象的创建和销毁是相对耗费资源的操作。
因此,应尽量减少不必要的对象创建和销毁。
可以通过对象复用、使用对象池等方式来实现。
例如,在一个循环中,如果每次都创建一个新的对象,会导致大量的内存分配和垃圾回收操作。
可以将对象创建放在循环外部,或者使用对象池来重复利用已经创建的对象。
另外,使用基本数据类型代替对象类型也能减少对象创建的开销。
比如,如果只需要存储一个整数,使用`int`类型而不是`Integer`对象。
三、字符串操作的优化字符串操作在很多应用中都非常常见,因此对字符串操作进行优化也能显著提升性能。
避免频繁的字符串拼接操作,因为这会创建新的字符串对象。
可以使用`StringBuilder`或`StringBuffer`类来进行字符串的拼接,它们在内部进行了优化,能够减少对象的创建。
在字符串比较时,如果不需要区分大小写,可以使用`equalsIgnoreCase()`方法,而不是先将字符串转换为小写或大写后再进行比较,这样可以减少额外的字符串转换操作。
四、合理使用缓存缓存是一种常见的性能优化手段。
可以将经常使用的数据或计算结果缓存起来,避免重复计算或重复获取数据。
jvm常用调优参数
JVM是JavaVirtualMachine的缩写,是Java程序运行的核心。
JVM的调优是优化Java应用程序性能的重要一环,其中调优参数的合理设置是关键。
以下是常用的JVM调优参数:
1. -Xms:设置JVM的初始内存大小,默认为物理内存的
1/64。
2. -Xmx:设置JVM的最大内存大小,超出该内存大小后会触发垃圾回收。
3. -Xmn:设置年轻代的大小,一般设置为总内存的1/3或
1/4。
4. -XX:SurvivorRatio:设置年轻代中Eden区和Survivor区的比例,默认值为8。
5. -XX:NewRatio:设置新生代和老年代的比例,默认值为2。
6. -XX:MaxPermSize:设置永久代的大小,一般设置为
256MB。
7. -XX:+UseConcMarkSweepGC:使用CMS垃圾回收器,可以减少内存抖动。
8. -XX:+UseParallelGC:使用并行垃圾回收器,可提高垃圾回收效率。
9. -XX:+HeapDumpOnOutOfMemoryError:当JVM内存溢出时,生成堆转储文件。
10. -XX:+PrintGCDetails:打印垃圾回收的详细信息。
以上是常用的JVM调优参数,通过合理地设置参数,可以优化Java应用程序的性能。
JVM性能优化,Part 1 ―― JVM简介众所周知,Java应用程序是运行在JVM上的,但是你对JVM有所了解么?作为这个系列文章的第一篇,本文将对经典Java虚拟机的运行机制做简单介绍,内容包括―一次编写,到处运行‖的利弊、垃圾回收的基本原理、常用垃圾回收算法的示例和编译器优化等。
后续的系列文章将会JVM性能优化的内容进行介绍,包括新一代JVM的设计思路,以及如何支持当今Java应用程序对高性能和高扩展性的要求。
如果你是一名程序员,那么毫无疑问,你肯定有过某种兴奋的感觉,就像是当一束灵感之光照亮了你思考方向,又像是神经元最终建立连接,又像是你解放思想开拓了新的局面。
就我个人来说,我喜欢这种学习新知识的感觉。
我在工作时就常常会有这种感觉,我的工作会涉及到一些JVM的相关技术,这着实令我兴奋,尤其是工作涉及到垃圾回收和JVM性能优化的时候。
在这个系列中,我希望可以与你分享一些这方面的经验,希望你也会像我一样热爱JVM相关技术。
这个系列文章主要面向那些想要裂解JVM底层运行原理的Java程序员。
文章立足于较高的层面展开讨论,内容涉及到垃圾回收和在不影响应用程序运行的情况下对安全快速的释放/分配内存。
你将对JVM的核心模块有所了解:垃圾回收、GC算法、编译器行为,以及一些常用优化技巧。
此外,还会讨论为什么对Java做基准测试(benchmark)是件很困难的事,并提供一些建议来帮助做基准测试。
最后,将会介绍一些JVM和GC的前沿技术,内容涉及到Azul的Zing JVM,IBM JVM和Oracle的Garbage First(G1)垃圾回收器。
希望在阅读此系列文章后,你能对影响Java伸缩性的因素有所了解,并且知道这些因素是如何影响Java开发的,如何使Java难以优化的。
希望会你有那种发自内心的惊叹,并且能够激励你为Java做一点事情:拒绝限制,努力改变。
如果你还没准备好为开源事业贡献力量,希望本系列文章可以为你指明方向。
Resin服务器配置指南resin虚拟内存设置文章分类:Java编程show grants for root@localhost;说明RESIN_HOME - 表示resin的安装目录-Xms512m - 表示初始占用内存512MB-Xmx1024m - 表示最在可占用内存1024MBResin 3.0.x Linux下修改位置:RESIN_HOME\bin\httpd.sh 文件中找到args= 这行,修改成args="-J-server -Xms512m -Xmx1024m"设置JAVA虚拟机的内存使用量。
Windows下httpd.exe -Xms512m -Xmx1024mResin 3.1.x 同时适用于Linux和Windows修改位置:RESIN_HOME\conf\resin.conf找到如下内容<jvm-arg>-Xmx256m</jvm-arg><jvm-arg>-Xss1m</jvm-arg>修改成如下:<jvm-arg>-Xms512m</jvm-arg><jvm-arg>-Xmx1024m</jvm-arg><jvm-arg>-Xss1m</jvm-arg>3Jdk和Resin安装步骤1. 下载jdk linux版本, j2sdk-1_4_2_10-linux-i586.bin。
2. 下载resin-2.1.17.tar.gz。
或更好版本3. 直接输入:j2sdk-1_4_2_10-linux-i586.bin就可以安装成功。
本身它有安装脚本。
4. 修改用户根目录下配置文件。
(1)ls -a 查看文件(2)vi .bash_profile 添加:exportJAVA_HOME=/home/usboss/j2sdk1.4.2_10/Note:配置这个文件类似于windows的配置windows的环境变量。
JVM参数参数调优JVM(Java Virtual Machine)是Java虚拟机的缩写,它是Java程序运行的环境。
在运行Java程序时,可以通过调优JVM参数来提高程序的性能和稳定性。
下面将详细介绍一些常见的JVM参数以及如何进行参数调优。
1.内存参数调优:- -Xms:设置JVM的初始堆大小,即JVM启动时占用的内存大小。
可以通过增加-Xms参数来增加初始堆大小,从而减少GC(Garbage Collection)次数,提高程序的响应速度。
- -Xmx:设置JVM的最大堆大小,即JVM能够使用的最大内存大小。
可以通过增加-Xmx参数来增加最大堆大小,从而让程序能够处理更多的数据量或者更大的数据结构。
2.垃圾回收参数调优:- -XX:+UseSerialGC:使用串行垃圾回收器,适用于小型应用或开发环境。
串行垃圾回收器是单线程运行的,适合对资源比较敏感的环境。
- -XX:+UseParallelGC:使用并行垃圾回收器,适用于多核CPU的服务器。
并行垃圾回收器使用多个线程来进行垃圾回收,提高垃圾回收的效率。
- -XX:+UseConcMarkSweepGC:使用CMS(Concurrent Mark Sweep)垃圾回收器,适用于响应时间敏感的应用。
CMS垃圾回收器采用并发的方式进行垃圾回收,减少了垃圾回收的停顿时间。
- -XX:+UseG1GC:使用G1(Garbage First)垃圾回收器,适用于大型内存和多核CPU的情况。
G1垃圾回收器将内存分成多个固定大小的区域,更加高效地处理大对象。
3.线程参数调优:- -XX:ParallelGCThreads:设置并行垃圾回收的线程数量。
可以根据CPU的核心数来设置线程数量,提高垃圾回收的效率。
- -XX:MaxGCPauseMillis:设置垃圾回收的最大停顿时间。
可以根据程序的性能要求来设置最大停顿时间,避免长时间的垃圾回收导致程序的响应速度下降。
Java语言中的JVM优化技巧Java虚拟机(JVM)是Java语言的核心部分,它是一种运行在操作系统之上的虚拟计算机,负责Java程序的编译、解释和执行。
由于JVM是Java语言的运行环境,JVM的性能对于Java程序的性能也具有至关重要的影响。
因此,对于Java程序的开发者来说,优化JVM是非常重要的任务之一。
1. 内存管理优化Java语言最大的优势是安全、简单易用、跨平台等特点,但最严重的弱点是内存泄漏。
因为Java语言是基于垃圾收集器的运行机制,例如在程序中使用的对象被引用之后并且没有被释放,JVM会一直保留这种引用,因此在程序运行的过程中就会产生内存泄漏。
为了提高程序的内存利用率,需要对内存管理进行优化:- 合理设置堆内存大小Java中的堆内存是所有对象和类的存储空间,通过-Xmx和-Xms设置堆内存大小,来平衡程序的性能与内存占用,尽可能地避免full GC和OOM,推荐使用-Xms和-Xmx参数为同一值。
- 垃圾收集器的选择JVM的垃圾收集器是指定在运行Java程序时管理Java对象的内存分配和释放策略的工具。
目前,Oracle提供了七种垃圾收集器。
为了达到最佳性能,需要根据应用程序的特点选择合适的垃圾收集器。
- 定期执行GC保证2s内执行一次gc,这种周期时间既不会太长,也不能太短。
因为如果gc时间过长,会影响程序正常运行;而如果gc过于频繁,会导致程序的吞吐量下降。
2. 线程优化Java虚拟机已经在JDK1.5版本时引入了ThreadLocal,它是一种非常好的Java语言中的线程优化技巧。
如果使用得当,ThreadLocal可以帮助程序减少同步操作,避免线程池的枷锁等问题。
以下为ThreadLocal的使用方式:// 定义一个全局的ThreadLocal变量private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>(){// 覆盖初始化方法@Overrideprotected SimpleDateFormat initialValue(){return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); }};// 主线程中设置默认时间格式public static void main(String args[]){System.out.println(threadLocal.get().format(new Date()));}// 其他线程中设置时间格式new Thread(new Runnable(){@Overridepublic void run(){threadLocal.set(new SimpleDateFormat());System.out.println(threadLocal.get().format(new Date()));}}).start();ThreadLocal是基于JVM的,它的使用不需要进行任何锁操作或者同步措施,这样就可以避免很多线程同步操作所带来的额外的系统开销。
JVM调优参数详解GC有两种类型:Scavenge GC 和Full GC1、Scavenge GC⼀般情况下,当新对象⽣成,并且在Eden申请空间失败时,就会触发Scavenge GC,堆的Eden区域进⾏GC,清除⾮存活对象,并且把尚且存活的对象移动到Survivor的两个区中。
2、Full GC对整个堆进⾏整理,包括Young、Tenured和Perm。
Full GC ⽐Scavenge GC要慢,因此应该尽可能减少Full GC,有如下原因可能导致Full GCa、Tenured被写满;b、Perm域被写满c、System.gc()被显⽰调⽤d、上⼀次GC之后Heap的各域分配策略动态变化;-Xmx512m -Xms512m -Xmn192m -Xss128kJVM中最⼤堆⼤⼩受三⽅⾯限制,相关操作系统的数据模型(32位还是64位)限制;系统的可⽤虚拟内存限制;系统的可⽤物理内存限制-Xmx512m:设置JVM实例堆最⼤可⽤内存为512M。
-Xms512m:设置JVM促使内存为512m。
此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn192m设置年轻代⼤⼩为192m。
整个JVM内存⼤⼩=年轻代⼤⼩ + 年⽼代⼤⼩ + 持久代⼤⼩。
持久代⼀般固定⼤⼩为64m,所以增⼤年轻代后,将会减⼩年⽼代⼤⼩。
此值对系统性能影响较⼤,Sun官⽅推荐配置为整个堆的3/8。
-Xss128k设置每个线程的堆栈⼤⼩。
JDK5.0以后每个线程堆栈⼤⼩为1M,以前每个线程堆栈⼤⼩为256K。
更具应⽤的线程所需内存⼤⼩进⾏调整。
在相同物理内存下,减⼩这个值能⽣成更多的线程。
但是操作系统对⼀个进程内的线程数还是有限制的,不能⽆限⽣成,经验值在3000~5000左右。
注意下⾯问题:(1)增加Heap的⼤⼩虽然会降低GC的频率,但也增加了每次GC的时间。
并且GC运⾏时,所有的⽤户线程将暂停,也就是GC期间,Java应⽤程序不做任何⼯作。
jvm 调优参数JVM调优参数JVM(Java Virtual Machine)调优是指通过调整JVM的参数,以提高Java应用程序的性能和稳定性。
JVM参数的设置对应用程序的运行效果和资源利用情况具有重要影响。
在本文中,将介绍一些常用的JVM调优参数,并解释它们的作用。
1. 堆内存参数- -Xms: 初始堆内存大小。
该参数指定JVM启动时堆内存的初始大小。
- -Xmx: 最大堆内存大小。
该参数指定JVM运行时堆内存能达到的最大限制。
- -Xmn: 年轻代内存大小。
该参数指定了年轻代的大小。
- -XX:NewRatio: 年轻代和老年代的比例。
该参数用来设置年轻代与老年代的比例,默认为2,即年轻代占整个堆内存的1/3。
2. 垃圾回收参数- -XX:+UseSerialGC: 使用串行垃圾回收器。
该参数在单核处理器系统上比较适用,回收时会暂停应用程序的执行。
- -XX:+UseParallelGC: 使用并行垃圾回收器。
该参数在具有多个处理器的系统上比较适用,可以并行地进行垃圾回收。
- -XX:+UseConcMarkSweepGC: 使用并发标记-清除垃圾回收器。
该参数在较大堆内存的情况下比较适用,可以并发地进行垃圾回收,减少暂停时间。
- -XX:SurvivorRatio: 幸存区比例。
该参数用来设置eden区与survivor区的比例,默认为8,即eden区占整个年轻代的8/10。
- -XX:MaxTenuringThreshold: 最大晋升年龄。
该参数用来设置对象从eden区到survivor区晋升的最大年龄。
3. 线程参数- -XX:ParallelGCThreads: 垃圾回收的线程数。
- -XX:ConcGCThreads: 并发垃圾回收的线程数。
- -XX:ThreadStackSize: 线程栈的大小。
4. 类加载参数- -XX:MetaspaceSize: 元空间大小。
该参数指定元空间的初始大小。
JVM参数参数调优随着Java应用程序的发展和复杂性增加,JVM参数的调优成为了提升应用程序性能和稳定性的重要方面。
正确地配置JVM参数,可以最大限度地利用系统资源,并优化垃圾回收和内存管理。
以下是关于JVM参数调优的一些建议和指导。
1.内存参数- -Xmx:指定最大堆内存大小,建议设置为物理内存的70-80%。
- -Xms:指定初始堆内存大小,建议和-Xmx设置相同,避免堆内存大小变化频繁。
- -Xmn:指定年轻代大小,建议设置为整个堆内存的1/4到1/3- -XX:NewRatio:指定新生代和老年代的比例,默认为2,可以根据应用的特性进行微调。
2.垃圾回收参数- -XX:+UseParallelGC:启用并行垃圾回收,并行垃圾回收会使用多个线程进行垃圾回收操作,适用于多核CPU。
- -XX:+UseConcMarkSweepGC:启用并发标记清除垃圾回收算法,可以降低停顿时间。
- -XX:ParallelGCThreads:设置并行垃圾回收线程数,可以根据CPU核心数进行调整。
- -XX:CMSInitiatingOccupancyFraction:设置CMS回收器开始执行垃圾回收的Heap占用率阈值,默认为92%。
- -XX:+ExplicitGCInvokesConcurrent:当调用System.gc(时,执行并发垃圾回收。
3.线程参数- -Xss:指定每个线程的堆栈大小,默认为512k,如果应用程序创建了大量的线程,可以适当增加该值。
- -XX:ThreadStackSize:和-Xss功能相同,可以单独设置一些线程的堆栈大小。
4.类加载参数- -XX:+TraceClassLoading:打印类加载信息,用于排查类加载相关的问题。
- -XX:+TraceClassUnloading:打印类卸载信息,用于排查类卸载相关的问题。
- -XX:+UseParNewGC:启用并行垃圾回收的新生代收集器,适用于多核CPU。
JVM 启动参数总结1.设置服务器端的JVM:JAVA_OPTS="-server -Xms3000m -Xmx3000m -Xss512k"-server:一定要作为第一个参数,在多个CPU时性能佳-Xms:初始Heap大小,使用的最小内存-Xmx:java heap最大值,使用的最大内存上面两个值一般设置为同样的大小。
-Xss:每个线程的Stack大小-verbose:gc 现实垃圾收集信息-Xloggc:gc.log 指定垃圾收集日志文件刚刚了解到的一些参数(待实践测试)-Xmn:young generation的heap大小,一般设置为Xmx的3、4分之一-XX:+UseParNewGC :缩短minor收集的时间-XX:+UseConcMarkSweepGC :缩短major收集的时间提示:此选项在Heap Size 比较大而且Major收集时间较长的情况下使用更合适/usr/local/jdk/bin/java -Dresin.home=/usr/local/resin -server -Xms1800M -Xmx1800M -Xmn300M-Xss512K -XX:PermSize=300M -XX:MaxPermSize=300M -XX:SurvivorRatio=8-XX:MaxTenuringThreshold=5 -XX:GCTimeRatio=19 -Xnoclassgc -XX:+DisableExplicitGC-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection-XX:CMSFullGCsBeforeCompaction=0 -XX:-CMSParallelRemarkEnabled-XX:CMSInitiatingOccupancyFraction=70 -XX:SoftRefLRUPolicyMSPerMB=0-XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC-Xloggc:log/gc.log完全只用上面几个参数是不够的。