ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>大片网站久久,久久久亚洲国产,国产区在线观看成人精品http://www.aygfsteel.com/stevenjohn/category/52895.html那些青春的岁æœ?/description>zh-cnMon, 23 Mar 2015 09:08:30 GMTMon, 23 Mar 2015 09:08:30 GMT60 Java¾~–译器、JVM、解释器http://www.aygfsteel.com/stevenjohn/archive/2015/03/23/423743.htmlabinabinMon, 23 Mar 2015 07:23:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2015/03/23/423743.htmlhttp://www.aygfsteel.com/stevenjohn/comments/423743.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2015/03/23/423743.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/423743.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/423743.htmlJava è™šæ‹Ÿæœ?JVM)是可˜qè¡ŒJava ä»£ç çš„假惌™®¡½Ž—机。只要根据JVM规格描述ž®†è§£é‡Šå™¨¿UÀL¤åˆ°ç‰¹å®šçš„计算æœÞZ¸ŠåQŒå°±èƒ½ä¿è¯ç»˜q‡ç¼–译的ä»ÖM½•Java代码能够在该¾pȝ»Ÿä¸Šè¿è¡Œã€‚本文首先简要介¾lä»ŽJavaæ–‡äšg的编译到最¾lˆæ‰§è¡Œçš„˜q‡ç¨‹åQŒéšåŽå¯¹JVM规格描述作一说明ã€?/span>
  
  一.Java源文件的¾~–译ã€?a target="_blank" style="color: #336699; text-decoration: none;">下蝲 ã€è§£é‡Šå’Œæ‰§è¡Œ 
  Java应用½E‹åºçš„开发周期包括编译ã€?/span>下蝲 ã€è§£é‡Šå’Œæ‰§è¡Œå‡ ä¸ªéƒ¨åˆ†ã€‚Java¾~–译½E‹åºž®†Javaæºç¨‹åºç¿»è¯‘äØ“(f¨´)JVM可执行代ç ?字节码。这一¾~–译˜q‡ç¨‹åŒC/C++ çš?¾~–译有些不同。当C¾~–译器编译生成一个对象的代码æ—Óž¼Œè¯¥ä»£ç æ˜¯ä¸ºåœ¨æŸä¸€ç‰¹å®š¼‹¬äšgòq›_°˜qè¡Œè€Œäñ”生的。因此,在编译过½E‹ä¸­åQŒç¼–译程序通过查表ž®†æ‰€æœ‰å¯¹½W¦å·çš„引 用è{æ¢äØ“(f¨´)特定的内存偏¿U»é‡åQŒä»¥ä¿è¯½E‹åº˜qè¡Œã€‚Java¾~–译器却不将对变量和æ–ÒŽ(gu¨©)³•çš„å¼•ç”¨ç¼–è¯‘äØ“(f¨´)数值引用,也不¼‹®å®š½E‹åºæ‰§è¡Œ˜q‡ç¨‹ä¸­çš„内存布局åQŒè€Œæ˜¯ž®†è¿™äº›ç¬¦å?引用信息保留在字节码中,ç”Þp§£é‡Šå™¨åœ¨è¿è¡Œè¿‡½E‹ä¸­åˆ›ç«‹å†…存布局åQŒç„¶åŽå†é€šè¿‡æŸ¥è¡¨æ¥ç¡®å®šä¸€ä¸ªæ–¹æ³•所在的地址。这样就有效的保证了(ji¨£n)Java的可¿UÀL¤æ€§å’Œå®‰å…¨ æ€§ã€?/span>
  
   ˜qè¡ŒJVM字节码的工作是由解释器来完成的。解释执行过½E‹åˆ†ä¸‰éƒ¨˜q›è¡ŒåQšä»£ç çš„装入、代码的校验和代码的执行。装入代码的工作ç”?¾c»è£…载器"åQˆclass loaderåQ‰å®Œæˆã€‚类装蝲器负责装入运行一个程序需要的所有代码,˜q™ä¹ŸåŒ…括½E‹åºä»£ç ä¸­çš„¾cÀL‰€¾l§æ‰¿çš„类和被其调用的¾c…R€‚当¾c»è£…载器装入一个类æ—Óž¼Œè¯¥ç±»è¢«æ”¾ 在自å·Þqš„名字½Iºé—´ä¸­ã€‚除äº?ji¨£n)通过½W¦å·å¼•用自己名字½Iºé—´ä»¥å¤–的类åQŒç±»ä¹‹é—´æ²¡æœ‰å…¶ä»–办法可以影响其他¾c…R€‚在本台计算æœÞZ¸Šçš„æ‰€æœ‰ç±»éƒ½åœ¨åŒä¸€åœ°å€½Iºé—´å†…,而所有从å¤?部引˜q›çš„¾c»ï¼Œéƒ½æœ‰ä¸€ä¸ªè‡ªå·Þq‹¬ç«‹çš„名字½Iºé—´ã€‚这使得本地¾c»é€šè¿‡å…׃ín相同的名字空间获得较高的˜qè¡Œæ•ˆçއåQŒåŒæ—¶åˆä¿è¯å®ƒä»¬ä¸Žä»Žå¤–部引进的类不会(x¨¬)ç›æ€º’影响。当装入 äº?ji¨£n)运行程序需要的所有类后,解释器便可确定整个可执行½E‹åºçš„内存布局。解释器为符号引用同特定的地址½Iºé—´å»ºç«‹å¯¹åº”关系å?qi¨¢ng)查询表。通过在这一阶段¼‹®å®šä»£ç çš?内存布局åQŒJava很好地解决了(ji¨£n)ç”Þp¶…¾cÀL”¹å˜è€Œä‹É子类崩溃的问题,同时也防止了(ji¨£n)代码对地址的非法访问ã€?/span>
  
  随后åQŒè¢«è£…入的代码由字节码校验器˜q›è¡Œ‹‚€(g¨¨)查。校验器可发现操作数栈溢出,非法数据¾cÕdž‹è½¬åŒ–½{‰å¤š¿Ué”™è¯¯ã€‚通过校验后,代码便开始执行了(ji¨£n)ã€?/span>
  
  Java字节码的执行有两¿Uæ–¹å¼ï¼š(x¨¬)
  1.åÏx—¶¾~–译方式åQšè§£é‡Šå™¨å…ˆå°†å­—节码编译成机器码,然后再执行该机器码ã€?/span>
  2.解释执行方式åQšè§£é‡Šå™¨é€šè¿‡æ¯æ¬¡è§£é‡Šòq¶æ‰§è¡Œä¸€ž®æ®µä»£ç æ¥å®ŒæˆJava字节码程 序的所有操作ã€?/span>
  通常采用的是½W¬äºŒ¿Uæ–¹æ³•。由于JVM规格描述å…ähœ‰­‘›_¤Ÿçš„灵‹zÀL€§ï¼Œ˜q™ä‹Éå¾—å°†å­—èŠ‚ç ç¿»è¯‘äØ“(f¨´)机器代码的工ä½?/span>
  
  å…ähœ‰è¾ƒé«˜çš„æ•ˆçŽ‡ã€‚å¯¹äºŽé‚£äº›å¯¹˜qè¡Œé€Ÿåº¦è¦æ±‚较高的应用程序,解释器可ž®†Javaå­—èŠ‚ç å³æ—¶ç¼–è¯‘äØ“(f¨´)机器码,从而很好地保证äº?ji¨£n)Java代码的可¿UÀL¤æ€§å’Œé«˜æ€§èƒ½ã€?/span>
  
  äº?JVM规格描述 
   JVM的设计目标是提供一个基于抽象规格描˜q°çš„è®¡ç®—æœºæ¨¡åž‹ï¼Œä¸ø™§£é‡Šç¨‹åºå¼€å‘äh员提很好的灵‹zÀL€§ï¼ŒåŒæ—¶ä¹Ÿç¡®ä¿Java代码可在½W¦åˆè¯¥è§„范的ä»ÖM½•¾pȝ»Ÿä¸Šè¿ 行。JVM对其实现的某些方面给å‡ÞZº†(ji¨£n)具体的定义,特别是对Java可执行代码,卛_­—节码(Bytecode)的格式给å‡ÞZº†(ji¨£n)明确的规根{€‚这一规格包括操作ç ?和操作数的语法和数倹{€æ ‡è¯†ç¬¦çš„æ•°å€ÆD¡¨½Cºæ–¹å¼ã€ä»¥å?qi¨¢ng)Java¾cÀL–‡ä»¶ä¸­çš„Java对象、常量缓冲池在JVMçš?/span>存储 æ˜ è±¡ã€‚è¿™äº›å®šä¹‰äØ“(f¨´)JVM解释器开发äh员提供了(ji¨£n)所需的信息和开发环境。Java的设计者希望给开发äh员以随心(j¨©)所‹Æ²ä‹É用Java的自由ã€?/span>
  
  JVM定义äº?ji¨£n)控制Java代码解释执行和具体实现的五种规格åQŒå®ƒä»¬æ˜¯åQ?/span>
  JVM指ä×o(h¨´)¾pȝ»Ÿ
  JVM寄存�/span>
  JVM栈结�/span>
  JVM¼„Žç‰‡å›žæ”¶å ?/span>
  JVM存储 åŒ?/span>
  
  2.1JVM指ä×o(h¨´)¾pȝ»Ÿ
  
   JVM指ä×o(h¨´)¾pȝ»ŸåŒå…¶ä»–计½Ž—机的指令系¾lŸæžå…¶ç›¸ä¼¹{€‚Java指ä×o(h¨´)也是ç”?操作码和操作æ•îC¸¤éƒ¨åˆ†¾l„成。操作码ä¸?位二˜q›åˆ¶æ•ŽÍ¼Œæ“ä½œæ•°è¿›ç´§éšåœ¨æ“ä½œç çš„后面,光™•¿åº¦æ ¹æ®éœ€è¦è€Œä¸åŒã€‚操作码用于指定一条指令操作的性质åQˆåœ¨˜q™é‡Œæˆ‘们é‡?用汇¾~–符åïL(f¨¥ng)š„形式˜q›è¡Œè¯´æ˜ŽåQ‰ï¼Œå¦‚iload表示从存储器中装入一个整敎ͼŒanewarray表示ä¸ÞZ¸€ä¸ªæ–°æ•°ç»„分配½Iºé—´åQŒiand表示两个整数çš? ä¸?åQŒret用于‹¹ç¨‹æŽ§åˆ¶åQŒè¡¨½CÞZ»Žå¯ÒŽ(gu¨©)Ÿä¸€æ–ÒŽ(gu¨©)³•的调用中˜q”回。当长度大于8位时åQŒæ“ä½œæ•°è¢«åˆ†ä¸ÞZ¸¤ä¸ªä»¥ä¸Šå­—节存放。JVM采用äº?big endian"的编码方式来处理˜q™ç§æƒ…况åQŒå³é«˜ä½bits存放在低字节中。这å?Motorolaå?qi¨¢ng)å…¶ä»–çš„RISC CPU采用的编码方式是一致的åQŒè€Œä¸ŽIntel采用çš?little endian "的编码方式即低位bits存放在低位字节的æ–ÒŽ(gu¨©)³•不同ã€?/span>
  
  Java指ä×o(h¨´)¾pȝ»Ÿæ˜¯ä»¥Java语言的实çŽîCØ“(f¨´)目的设计的,其中包含äº?ji¨£n)用于调用方法和监视多先½E‹ç³»¾lŸçš„æŒ‡ä×o(h¨´)。Javaçš?位操作码的长度ä‹Éå¾—JVM最多有256¿UæŒ‡ä»¤ï¼Œç›®å‰å·²ä‹É用了(ji¨£n)160多种操作码ã€?/span>
  
  2.2JVM指ä×o(h¨´)¾pȝ»Ÿ
  
   所有的CPU均包含用于保存系¾lŸçŠ¶æ€å’Œå¤„ç†å™¨æ‰€éœ€ä¿¡æ¯çš„å¯„å­˜å™¨¾l„。如果虚拟机定义较多的寄存器åQŒä¾¿å¯ä»¥ä»Žä¸­å¾—到更多的信息而不必对栈或内存˜q›è¡Œè®‰K—®åQŒè¿™ 有利于提高运行速度。然而,如果虚拟æœÞZ¸­çš„寄存器比实际CPU的寄存器多,在实现虚拟机时就ä¼?x¨¬)占用处理器大量的时间来用常规存储器模拟寄存器,˜q™åè€Œä¼š(x¨¬)é™?低虚拟机的效率。针对这¿Uæƒ…况,JVM只设¾|®äº†(ji¨£n)4个最为常用的寄存器。它们是åQ?/span>
  pc½E‹åºè®¡æ•°å™?/span>
  optop操作数栈™å¶æŒ‡é’?/span>
  frame当前执行环境指针
  vars指向当前执行环境中第一个局部变量的指针
ã€€ã€€æ‰€æœ‰å¯„å­˜å™¨å‡äØ“(f¨´)32位。pc用于记录½E‹åºçš„æ‰§è¡Œã€‚optop,frameå’Œvars用于记录指向Java栈区的指针ã€?/span>
  
  2.3JVM栈结�/span>
  
ã€€ã€€ä½œäØ“(f¨´)åŸÞZºŽæ ˆç»“构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后åQŒä¾¿ä¸ø™¯¥ä»£ç ä¸­ä¸€ä¸ªç±»çš„æ¯ä¸€ä¸ªæ–¹æ³•创å»ÞZ¸€ä¸ªæ ˆæ¡†æž¶åQŒä»¥ä¿å­˜è¯¥æ–¹æ³•的状态信息。每个栈框架包括以下三类信息åQ?/span>
  局部变�/span>
  执行环境
  操作数栈
  
  局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量�/span>
   执行环境用于保存解释器对Java字节码进行解释过½E‹ä¸­æ‰€éœ€çš„信息。它们是åQšä¸Š‹Æ¡è°ƒç”¨çš„æ–ÒŽ(gu¨©)³•、局部变量指针和操作数栈的栈™å¶å’Œæ ˆåº•指针。执行环境是一ä¸?执行一个方法的控制中心(j¨©)。例如:(x¨¬)如果解释器要执行iadd(整数加法)åQŒé¦–先要从frame寄存器中扑ֈ°å½“前执行环境åQŒè€ŒåŽä¾¿ä»Žæ‰§è¡ŒçŽ¯å¢ƒä¸­æ‰¾åˆ°æ“ä½œæ•°æ ˆï¼Œ 从栈™å¶å¼¹å‡ÞZ¸¤ä¸ªæ•´æ•°è¿›è¡ŒåŠ æ³•è¿½Ž—,最后将¾l“果压入栈顶ã€?/span>
  操作数栈用于存储˜qç®—所需操作数及(qi¨¢ng)˜qç®—的结果ã€?/span>
  
  2.4JVM¼„Žç‰‡å›žæ”¶å ?/span>
  
  Java¾cȝš„实例所需的存储空间是在堆上分配的。解释器具体承担为类实例分配½Iºé—´çš„å·¥ä½œã€‚è§£é‡Šå™¨åœ¨äØ“(f¨´)一个实例分配完存储½Iºé—´åŽï¼Œä¾¿å¼€å§‹è®°å½•对该实例所占用的内存区域的使用。一旦对象ä‹É用完毕,便将其回收到堆中ã€?/span>
   在Java语言中,除了(ji¨£n)newè¯­å¥å¤–æ²¡æœ‰å…¶ä»–æ–¹æ³•äØ“(f¨´)一对象甌™¯·å’Œé‡Šæ”‘Ö†…存。对内存˜q›è¡Œé‡Šæ”¾å’Œå›žæ”¶çš„工作是由Java˜qè¡Œ¾pȝ»Ÿæ‰¿æ‹…的。这允许Java˜qè¡Œ ¾pȝ»Ÿçš„设计者自己决定碎片回收的æ–ÒŽ(gu¨©)³•。在SUN公司开发的Java解释器和Hot Java环境中,¼„Žç‰‡å›žæ”¶ç”¨åŽå°çº¿½E‹çš„æ–¹å¼æ¥æ‰§è¡Œã€‚è¿™ä¸ä½†ä¸ø™¿è¡Œç³»¾lŸæä¾›äº†(ji¨£n)良好的性能åQŒè€Œä¸”使程序设计äh员摆è„׃º†(ji¨£n)自己控制内存使用的风险ã€?/span>
  
  2.5JVM存储�/span>
  
   JVM有两¾cÕd­˜å‚¨åŒºåQšå¸¸é‡ç¼“冲池和方法区。常量缓冲池用于存储¾cÕd¿U°ã€æ–¹æ³•和字段名称以及(qi¨¢ng)串常量。方法区则用于存储Javaæ–ÒŽ(gu¨©)³•的字节码。对于这两种å­?储区域具体实现方式在JVM规格中没有明¼‹®è§„定。这使得Java应用½E‹åºçš„存储布局必须在运行过½E‹ä¸­¼‹®å®šåQŒä¾èµ–于具体òq›_°çš„实现方式ã€?/span>
  
  JVMæ˜¯äØ“(f¨´)Java字节码定义的一¿Uç‹¬ç«‹äºŽå…·ä½“òq›_°çš„规格描˜qŽÍ¼Œæ˜¯Javaòq›_°ç‹¬ç«‹æ€§çš„基础。目前的JVM˜q˜å­˜åœ¨ä¸€äº›é™åˆ¶å’Œä¸èƒöåQŒæœ‰å¾…于˜q›ä¸€æ­¥çš„完善åQŒä½†æ— è®ºå¦‚何åQŒJVM的思想是成功的ã€?/span>
  
  å¯ÒŽ(gu¨©)¯”分析åQšå¦‚果把Java原程序想象成我们çš?/span>C++ åŽ?½E‹åºåQŒJava原程序编译后生成的字节码ž®Þq›¸å½“于C++原程序编译后çš?0x86的机器码åQˆäºŒ˜q›åˆ¶½E‹åºæ–‡äšgåQ‰ï¼ŒJVM虚拟机相当于80x86计算机系 ¾l?Java解释器相当于80x86CPU。在80x86CPU上运行的是机器码åQŒåœ¨Java解释器上˜qè¡Œçš„æ˜¯Java字节码ã€?/span>
  
   Java解释器相当于˜qè¡ŒJava字节码的“CPU”,但该“CPU”不是通过¼‹¬äšg实现的,而是用èÊY件实现的。Java解释器实际上ž®±æ˜¯ç‰¹å®šçš„åã^åîC¸‹çš„一 个应用程序。只要实çŽîCº†(ji¨£n)特定òq›_°ä¸‹çš„解释器程序,Java字节码就能通过解释器程序在该åã^åîC¸‹˜qè¡ŒåQŒè¿™æ˜¯Javaè·¨åã^台的æ ÒŽ(gu¨©)œ¬ã€‚当前,òq¶ä¸æ˜¯åœ¨æ‰€æœ‰çš„òq›_° 下都有相应Java解释器程序,˜q™ä¹Ÿæ˜¯Javaòq¶ä¸èƒ½åœ¨æ‰€æœ‰çš„òq›_°ä¸‹éƒ½èƒ½è¿è¡Œçš„原因åQŒå®ƒåªèƒ½åœ¨å·²å®žçްäº?ji¨£n)Java解释器程序的òq›_°ä¸‹è¿è¡Œã€?br />

       Java主要靠Java虚拟机(JVMåQ‰åœ¨ç›®æ ‡ç çñ”实现òq›_°æ— å…³æ€§ã€‚JVM是一¿UæŠ½è±¡æœºå™¨ï¼Œå®ƒé™„着在具体操作系¾lŸä¹‹ä¸Šï¼Œæœ¬èínå…ähœ‰ä¸€å¥—虚机器指ä×o(h¨´)åQŒåƈ有自å·Þqš„æ ˆã€å¯„存器¾l„等。但JVM通常是在软äšg上而不是在¼‹¬äšg上实现。(目前åQŒSUN¾pȝ»Ÿå…¬å¸å·²ç»è®¾è®¡å®žçްäº?ji¨£n)Java芯片åQŒä¸»è¦ä‹É用在¾|‘络计算机NC上。另外,Java芯片的出çŽîC¹Ÿä¼?x¨¬)ä‹ÉJava更容易嵌入到家用ç”?sh¨´)器中。)(j¨ª)JVM是Javaòq›_°æ— å…³çš„基¼‹€åQŒåœ¨JVM上,有一个Java解释器用来解释Java¾~–译器编译后的程序。Java¾~–程人员在编写完软äšg后,通过Java¾~–译器将Javaæºç¨‹åºç¼–è¯‘äØ“(f¨´)JVM的字节代码。ä“Q何一台机器只要配备了(ji¨£n)Java解释器,ž®±å¯ä»¥è¿è¡Œè¿™ä¸ªç¨‹åºï¼Œè€Œä¸½Ž¡è¿™¿Uå­—节码是在何种òq›_°ä¸Šç”Ÿæˆçš„åQˆè¿‡½E‹å¦‚å›?所½Cºï¼‰(j¨ª)。另外,Java采用的是åŸÞZºŽIEEE标准的数据类型。通过JVM保证数据¾cÕdž‹çš„一致性,也确保了(ji¨£n)Javaçš„åã^台无å…Ïx€§ã€?nbsp;

½Ž€å•说åQŒjava的解释器只是一个基于虚拟机jvmòq›_°çš„程åº?nbsp;


]]>
setAccessiblehttp://www.aygfsteel.com/stevenjohn/archive/2015/03/23/423732.htmlabinabinSun, 22 Mar 2015 16:01:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2015/03/23/423732.htmlhttp://www.aygfsteel.com/stevenjohn/comments/423732.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2015/03/23/423732.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/423732.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/423732.htmlç”׃ºŽJDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以辑ֈ°æå‡åå°„速度的目çš?nbsp;


]]>
JAVA中JVM的重排序详细介绍http://www.aygfsteel.com/stevenjohn/archive/2015/03/22/423718.htmlabinabinSun, 22 Mar 2015 05:27:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2015/03/22/423718.htmlhttp://www.aygfsteel.com/stevenjohn/comments/423718.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2015/03/22/423718.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/423718.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/423718.html       é‡æŽ’序通常是编译器或运行时环境ä¸ÞZº†(ji¨£n)优化½E‹åºæ€§èƒ½è€Œé‡‡å–çš„å¯ÒŽ(gu¨©)Œ‡ä»¤è¿›è¡Œé‡æ–°æŽ’序执行的一¿Uæ‰‹ŒDüc(di¨£n)€‚é‡æŽ’åºåˆ†äØ“(f¨´)两类åQšç¼–译期重排序和˜qè¡ŒæœŸé‡æŽ’序åQŒåˆ†åˆ«å¯¹åº”编译时和运行时环境

åœ¨åÆˆå‘ç¨‹åºä¸­åQŒç¨‹åºå‘˜ä¼?x¨¬)特别关注不同进½E‹æˆ–¾U¿ç¨‹ä¹‹é—´çš„æ•°æ®åŒæ­¥ï¼Œç‰¹åˆ«æ˜¯å¤šä¸ªçº¿½E‹åŒæ—¶ä¿®æ”¹åŒä¸€å˜é‡æ—Óž¼Œå¿…须采取可靠的同步或其它措施保障数据被正¼‹®åœ°ä¿®æ”¹åQŒè¿™é‡Œçš„一条重要原则是åQšä¸è¦å‡è®¾æŒ‡ä»¤æ‰§è¡Œçš„™åºåºåQŒä½ æ— æ³•预知不同¾U¿ç¨‹ä¹‹é—´çš„æŒ‡ä»¤ä¼š(x¨¬)以何¿Ué¡ºåºæ‰§è¡Œã€?/p>

但是在单¾U¿ç¨‹½E‹åºä¸­ï¼Œé€šå¸¸æˆ‘们å®ÒŽ(gu¨©)˜“假设指ä×o(h¨´)是顺序执行的åQŒå¦åˆ™å¯ä»¥æƒ³è±¡ç¨‹åºä¼š(x¨¬)发生什么可怕的变化。理想的模型是:(x¨¬)各种指ä×o(h¨´)执行的顺序是唯一且有序的åQŒè¿™ä¸ªé¡ºåºå°±æ˜¯å®ƒä»¬è¢«¾~–写在代码中的顺序,与处理器或其它因素无养I¼Œ˜q™ç§æ¨¡åž‹è¢«ç§°ä½œé¡ºåºä¸€è‡´æ€§æ¨¡åž‹ï¼Œä¹Ÿæ˜¯åŸÞZºŽå†?#183;è¯ÞZ¾æ›ég½“¾pÈš„æ¨¡åž‹ã€‚当ç„?d¨°ng)ž¼Œ˜q™ç§å‡è®¾æœ¬èín是合理的åQŒåœ¨å®žè·µä¸­ä¹Ÿé²œæœ‰å¼‚常发生åQŒä½†äº‹å®žä¸Šï¼Œæ²¡æœ‰å“ªä¸ªçŽîC»£å¤šå¤„理器架构ä¼?x¨¬)采用这¿Uæ¨¡åž‹ï¼Œå› äØ“(f¨´)它是在是太低效了(ji¨£n)。而在¾~–译优化和CPU‹¹æ°´¾U¿ä¸­åQŒå‡ ä¹Žéƒ½æ¶‰åŠ(qi¨¢ng)到指令重排序ã€?/p>

¾~–译期重排序

¾~–译期重排序的典型就是通过调整指ä×o(h¨´)™åºåºåQŒåœ¨ä¸æ”¹å˜ç¨‹åºè¯­ä¹‰çš„前提下,ž®½å¯èƒ½å‡ž®‘寄存器的读取、存储次敎ͼŒå……分复用寄存器的存储倹{€?/p>

假设½W¬ä¸€æ¡æŒ‡ä»¤è®¡½Ž—ä¸€ä¸ªå€ÆDµ‹¾l™å˜é‡Aòq¶å­˜æ”‘Öœ¨å¯„存器中åQŒç¬¬äºŒæ¡æŒ‡ä×o(h¨´)与A无关但需要占用寄存器åQˆå‡è®‘Ö®ƒ?y¨­u)®†å ç”¨A所在的那个寄存器)(j¨ª)åQŒç¬¬ä¸‰æ¡æŒ‡ä×o(h¨´)使用Açš„å€ég¸”与第二条指ä×o(h¨´)无关。那么如果按照顺序一致性模型,A在第一条指令执行过后被攑օ¥å¯„存器,在第二条指ä×o(h¨´)执行时A不再存在åQŒç¬¬ä¸‰æ¡æŒ‡ä×o(h¨´)执行时A重新被读入寄存器åQŒè€Œè¿™ä¸ªè¿‡½E‹ä¸­åQŒA的值没有发生变化。通常¾~–译器都ä¼?x¨¬)交换第二和½W¬ä¸‰æ¡æŒ‡ä»¤çš„位置åQŒè¿™æ ïL(f¨¥ng)¬¬ä¸€æ¡æŒ‡ä»¤ç»“束时A存在于寄存器中,接下来可以直接从寄存器中è¯Õd–Açš„å€û|¼Œé™ä½Žäº?ji¨£n)重复读取的开销ã€?br />
重排序对于流水线的意�/strong>

çŽîC»£CPU几乎都采用流水线机制加快指ä×o(h¨´)的处理速度åQŒä¸€èˆ¬æ¥è¯ß_(d¨¢)¼Œä¸€æ¡æŒ‡ä»¤éœ€è¦è‹¥òq²ä¸ªCPUæ—‰™’Ÿå‘¨æœŸå¤„理åQŒè€Œé€šè¿‡‹¹æ°´¾U¿åƈ行执行,可以在同½{‰çš„æ—‰™’Ÿå‘¨æœŸå†…执行若òq²æ¡æŒ‡ä×o(h¨´)åQŒå…·ä½“做法简单地说就是把指ä×o(h¨´)åˆ†äØ“(f¨´)不同的执行周期,例如è¯Õd–、寻址、解析、执行等步骤åQŒåƈ攑֜¨ä¸åŒçš„元件中处理åQŒåŒæ—¶åœ¨æ‰§è¡Œå•å…ƒEU中,功能单元被分ä¸ÞZ¸åŒçš„å…ƒäšgåQŒä¾‹å¦‚加法元件、乘法元件、加载元件、存储元件等åQŒå¯ä»¥è¿›ä¸€æ­¥å®žçŽîC¸åŒçš„计算òq¶è¡Œæ‰§è¡Œã€?/p>

‹¹æ°´¾U¿æž¶æž„决定了(ji¨£n)指ä×o(h¨´)åº”è¯¥è¢«åÆˆè¡Œæ‰§è¡Œï¼Œè€Œä¸æ˜¯åœ¨™åºåºåŒ–æ¨¡åž‹ä¸­æ‰€è®¤äØ“(f¨´)的那栗÷€‚重排序有利于充分ä‹É用流水线åQŒè¿›è€Œè¾¾åˆ°è¶…标量的效果ã€?br />
¼‹®ä¿?r¨´n)åºåºæ€?/strong>

ž®½ç®¡æŒ‡ä×o(h¨´)在执行时òq¶ä¸ä¸€å®šæŒ‰ç…§æˆ‘们所¾~–写的顺序执行,但毋庸置疑的是,在单¾U¿ç¨‹çŽ¯å¢ƒä¸‹ï¼ŒæŒ‡ä×o(h¨´)执行的最¾lˆæ•ˆæžœåº”当与其在™åºåºæ‰§è¡Œä¸‹çš„æ•ˆæžœä¸€è‡ß_(d¨¢)¼Œå¦åˆ™˜q™ç§ä¼˜åŒ–便会(x¨¬)失去意义ã€?/p>

通常无论是在¾~–译期还是运行期˜q›è¡Œçš„æŒ‡ä»¤é‡æŽ’序åQŒéƒ½ä¼?x¨¬)满­‘³ä¸Šé¢çš„原则ã€?/p>

Java存储模型中的重排�/strong>

在Java存储模型åQˆJava Memory Model, JMMåQ‰ä¸­åQŒé‡æŽ’序是十分重要的一节,特别是在òq¶å‘¾~–程中。JMM通过happens-before法则保证™åºåºæ‰§è¡Œè¯­ä¹‰åQŒå¦‚果想要让执行操作B的线½E‹è§‚察到执行操作A的线½E‹çš„¾l“æžœåQŒé‚£ä¹ˆAå’ŒBž®±å¿…™åÀL»¡­‘³happens-before原则åQŒå¦åˆ™ï¼ŒJVM可以对它们进行ä“Q意排序以提高½E‹åºæ€§èƒ½ã€?/p>

volatileå…³é”®å­—å¯ä»¥ä¿è¯å˜é‡çš„å¯è§æ€§ï¼Œå› äØ“(f¨´)对volatile的操作都在Main Memory中,而Main Memory是被所有线½E‹æ‰€å…׃ín的,˜q™é‡Œçš„代价就是牺牲了(ji¨£n)性能åQŒæ— æ³•利用寄存器或CacheåQŒå› ä¸ºå®ƒä»¬éƒ½ä¸æ˜¯å…¨å±€çš„,无法保证可见性,可能产生脏读ã€?/p>

volatile˜q˜æœ‰ä¸€ä¸ªä½œç”¨å°±æ˜¯å±€éƒ¨é˜»æ­¢é‡æŽ’序的发生,对volatile变量的操作指令都不会(x¨¬)被重排序åQŒå› ä¸ºå¦‚果重排序åQŒåˆå¯èƒ½äº§ç”Ÿå¯è§æ€§é—®é¢˜ã€?/p>

在保证可见性方面,锁(包括昑ּé”ã€å¯¹è±¡é”åQ‰ä»¥å?qi¨¢ng)对原子变量的读写都可以¼‹®ä¿å˜é‡çš„可见性。但是实现方式略有不同,例如同步锁保证得到锁时从内存里重新读入数据刷新缓存,释放锁时ž®†æ•°æ®å†™å›žå†…存以保数据可见,而volatile变量òq²è„†éƒ½æ˜¯è¯Õd†™å†…å­˜ã€?/p>







]]>
重排序、内存可见性、Happens-before 关系http://www.aygfsteel.com/stevenjohn/archive/2015/03/22/423716.htmlabinabinSun, 22 Mar 2015 04:40:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2015/03/22/423716.htmlhttp://www.aygfsteel.com/stevenjohn/comments/423716.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2015/03/22/423716.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/423716.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/423716.htmlJava 内存模型

ç”׃ºŽ ConcurrentHashMap 是徏立在 Java 内存模型基础上的åQŒäØ“(f¨´)äº?ji¨£n)更好的理è§?ConcurrentHashMapåQŒè®©æˆ‘们首先来了(ji¨£n)解一ä¸?Java 的内存模型ã€?/p>

Java 语言的内存模型由一些规则组成,˜q™äº›è§„则¼‹®å®š¾U¿ç¨‹å¯¹å†…存的讉K—®å¦‚何排序以及(qi¨¢ng)何时可以¼‹®ä¿å®ƒä»¬å¯¹çº¿½E‹æ˜¯å¯è§çš„。下面我们将分别介绍 Java 内存模型的重排序åQŒå†…存可见性和 happens-before 关系ã€?/p>

重排�/h3>

内存模型描述äº?ji¨£n)程序的可能行äØ?f¨´)。具体的¾~–译器实现可以äñ”生ä“Q意它喜欢的代ç ?-- 只要所有执行这些代码äñ”生的¾l“æžœåQŒèƒ½å¤Ÿå’Œå†…存模型预测的结果保持一致。这为编译器实现者提供了(ji¨£n)很大的自由,包括操作的重排序ã€?/p>

¾~–译器生成指令的‹Æ¡åºåQŒå¯ä»¥ä¸åŒäºŽæºä»£ç æ‰€æš—示çš?#8220;昄¡„¶”版本。重排序后的指ä×o(h¨´)åQŒå¯¹äºŽä¼˜åŒ–执行以å?qi¨¢ng)成熟的全局寄存器分配算法的使用åQŒéƒ½æ˜¯å¤§æœ‰è„¾ç›Šçš„åQŒå®ƒä½¿å¾—½E‹åºåœ¨è®¡½Ž—性能上有äº?ji¨£n)很大的提升ã€?/p>

重排序类型包括:(x¨¬)

  • ¾~–译器生成指令的‹Æ¡åºåQŒå¯ä»¥ä¸åŒäºŽæºä»£ç æ‰€æš—示çš?#8220;昄¡„¶”版本ã€?/li>
  • å¤„ç†å™¨å¯ä»¥äØ•åºæˆ–è€…åÆˆè¡Œçš„æ‰§è¡ŒæŒ‡ä×o(h¨´)ã€?/li>
  • ¾~“å­˜ä¼?x¨¬)改变写入提交到ä¸Õd†…存的变量的次序ã€?/li>

内存可见�/h3>

ç”׃ºŽçŽîC»£å¯å…±äº«å†…å­˜çš„å¤šå¤„ç†å™¨æž¶æž„å¯èƒ½å¯ÆD‡´ä¸€ä¸ªçº¿½E‹æ— æ³•马上(甚至永远åQ‰çœ‹åˆ°å¦ä¸€ä¸ªçº¿½E‹æ“ä½œäñ”生的¾l“果。所ä»?Java 内存模型规定äº?JVM 的一¿Uæœ€ž®ä¿è¯ï¼š(x¨¬)什么时候写入一个变量对其他¾U¿ç¨‹å¯è§ã€?/p>

在现代可å…׃ín内存的多处理器体¾pȝ»“构中每个处理器都有自å·Þqš„¾~“å­˜åQŒåƈ周期性的与主内存协调一致。假讄¡º¿½E?A 写入一个变量å€?VåQŒéšåŽå¦ä¸€ä¸ªçº¿½E?B è¯Õd–变量 V çš„å€û|¼Œåœ¨ä¸‹åˆ—情况下åQŒçº¿½E?B è¯Õd–的值可能不是线½E?A 写入的最新å€û|¼š(x¨¬)

  • 执行¾U¿ç¨‹ A 的处理器把变é‡?V ¾~“存到寄存器中ã€?/li>
  • 执行¾U¿ç¨‹ A 的处理器把变é‡?V ¾~“存到自å·Þqš„¾~“存中,但还没有同步åˆäh–°åˆîC¸»å†…存中去ã€?/li>
  • 执行¾U¿ç¨‹ B 的处理器的缓存中有变é‡?V 的旧倹{€?/li>

Happens-before 关系

happens-before 关系保证åQšå¦‚果线½E?A 与线½E?B 满èƒö happens-before 关系åQŒåˆ™¾U¿ç¨‹ A 执行动作的结果对于线½E?B 是可见的。如果两个操作未æŒ?happens-before 排序åQŒJVM ž®†å¯ä»¥å¯¹ä»–们ä»ÀL„é‡æŽ’序ã€?/p>

下面介绍几个与理è§?ConcurrentHashMap 有关çš?happens-before 关系法则åQ?/p>

  1. ½E‹åº‹Æ¡åºæ³•则åQšå¦‚果在½E‹åºä¸­ï¼Œæ‰€æœ‰åЍä½?A 出现在动ä½?B 之前åQŒåˆ™¾U¿ç¨‹ä¸­çš„æ¯åЍä½?A éƒ?happens-before 于该¾U¿ç¨‹ä¸­çš„æ¯ä¸€ä¸ªåЍä½?Bã€?/li>
  2. 监视器锁法则åQšå¯¹ä¸€ä¸ªç›‘视器的解é”?happens-before 于每个后¾l­å¯¹åŒä¸€ç›‘视器的加锁ã€?/li>
  3. Volatile 变量法则åQšå¯¹ Volatile 域的写入操作 happens-before 于每个后¾l­å¯¹åŒä¸€ Volatile 的读操作ã€?/li>
  4. 传递性:(x¨¬)如果 A happens-before äº?BåQŒä¸” B happens-before CåQŒåˆ™ A happens-before Cã€?/li>


]]>
探秘Java 7新增垃圾回收器G1ç‰ÒŽ(gu¨©)€?/title><link>http://www.aygfsteel.com/stevenjohn/archive/2015/03/09/423325.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Mon, 09 Mar 2015 12:15:00 GMT</pubDate><guid>http://www.aygfsteel.com/stevenjohn/archive/2015/03/09/423325.html</guid><wfw:comment>http://www.aygfsteel.com/stevenjohn/comments/423325.html</wfw:comment><comments>http://www.aygfsteel.com/stevenjohn/archive/2015/03/09/423325.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/stevenjohn/comments/commentRss/423325.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/stevenjohn/services/trackbacks/423325.html</trackback:ping><description><![CDATA[<div>ã€?1CTO¾_ùN€‰è¯‘文】G1垃圾回收器(½Ž€¿U°G1 GCåQ‰æ˜¯JDK 7中Java HotSpot VM新引入的垃圾回收器,Java SE 6 Update 14中已¾låŒ…含了(ji¨£n)一个G1的体验版本(æ?1CTO之前的报å¯û|¼Œåœ¨Java SE 6 u14äº?月初ç™Õdœºæ—Óž¼ŒåŽŸæœ¬Sun的声明是åQšG1垃圾回收器需要收è´ÒŽ(gu¨©)–¹èƒ½ä‹É用。然而之后不久,Sun表示˜q™æ˜¯ä¸€ä¸ªè¯¯ä¼?x¨¬),修改了(ji¨£n)原本的发布声明åQŒåƈ表示现在以及(qi¨¢ng)ž®†æ¥å¯¹G1çš„ä‹É用都是完全免费的åQ‰ï¼ŒG1是设计用于替代HotSpot低åšg˜qŸçš„òq¶è¡Œæ ‡è®°/清除垃圾回收器(也叫做CMSåQ‰çš„ã€?/div><div></div><div>Java 7 G1属æ€?/div><div></div><div>G1是一个服务端垃圾回收器,有以下属性:(x¨¬)</div><div></div><div>◆òq¶è¡Œå’Œåƈ发性:(x¨¬)G1利用äº?ji¨£n)å½“ä»Šç¡¬ä»¶ä¸­å­˜åœ¨çš„åÆˆè¡Œæ€§ï¼Œå½“Java应用½E‹åºçš„线½E‹è¢«åœæ­¢æ—Óž¼Œå®ƒä‹É用所有可用的CPUåQˆæ ¸å¿?j¨©),¼‹¬äšg¾U¿ç¨‹½{‰ï¼‰(j¨ª)加速其停止åQŒåœ¨åœæ­¢˜q‡ç¨‹ä¸­è¿è¡ŒJava¾U¿ç¨‹æœ€ž®åŒ–整个堆栈ã€?/div><div></div><div>◆代:(x¨¬)和其他HotSpot GCä¸€æ øP¼ŒG1是一代,意味着它在处理新分配的对象åQˆå¹´è½ÖM»£åQ‰å’Œå·²ç»ç”Ÿå­˜äº?ji¨£n)一ŒD‰|—¶é—´çš„对象åQˆå¹´è€ä»£åQ‰æ—¶ä¼?x¨¬)不同,它主要集中于新对象上的垃圑֛žæ”¶æ´»åŠ¨ï¼Œå› äØ?f¨´)它们是最可能回收的,旧对象只是偶ž®?d¨¡ng)访问一下,对于大多数Java应用½E‹åºåQŒä»£çš„垃圑֛žæ”¶å¯¹äºŽæ›¿ä»£æ–¹æ¡ˆå…·æœ‰é‡è¦ä¼˜åŠÑ€?/div><div></div><div>◆压羃åQšå’ŒCMS不同åQŒG1ä¼?x¨¬)随旉™—´æŽ¨ç§»å¯¹å †æ ˆè¿›è¡ŒåŽ‹¾~©ï¼ŒåŽ‹ç¾ƒæ¶ˆé™¤äº?ji¨£n)潜在的¼„Žç‰‡é—®é¢˜åQŒç¡®ä¿é•¿æ—‰™—´˜qè¡Œçš„æ“ä½œæµç•…和一致ã€?/div><div></div><div>◆可预‹¹‹æ€§ï¼š(x¨¬)G1比CMS预测性更佻I¼Œ˜q™éƒ½æ˜¯ç”±äºŽæ¶ˆé™¤äº†(ji¨£n)¼„Žç‰‡é—®é¢˜å¸¦æ¥çš„好处,再也没有CMS中停止期间出现的负面影响åQŒå¦å¤–,G1有一个暂停预‹¹‹æ¨¡åž‹ï¼Œå…è®¸å®ƒæ»¡­‘»I¼ˆæˆ–很ž®‘è¶…˜q‡ï¼‰(j¨ª)暂停旉™—´ç›®æ ‡ã€?/div><div></div><div>Java 7 G1描述</div><div></div><div>和其它HotSpot GC相比åQŒG1采用äº?ji¨£n)ä¸€ä¸ªéžå¸æ€¸åŒçš„堆栈布局æ–ÒŽ(gu¨©)³•åQŒåœ¨G1中,òq´è½»ä»£å’Œòq´è€ä»£ä¹‹é—´æ²¡æœ‰ç‰©ç†éš”离åQŒç›¸åï¼Œå®ƒä»¬ä¹‹é—´æœ‰ä¸€ä¸ªè¿ž¾l­çš„堆栈åQŒè¢«åˆ†æˆå¤§å°ä¸€æ ïL(f¨¥ng)š„区域åQˆregionåQ‰ï¼Œòq´è½»ä»£å¯èƒ½æ˜¯ä¸€å¥—非˜qžç®‹çš„区域,òq´è€ä»£ä¹Ÿä¸€æ øP¼Œ˜q™å°±å…è®¸G1在年è½ÖM»£å’Œå¹´è€ä»£ä¹‹é—´ç‰|´»åœ°ç§»åŠ¨èµ„æºã€?/div><div></div><div>G1中的回收是通过消除暂停发生的,在此期间åQŒå¹¸å­˜è€…指的是回收集被转移到另一个区域,以便回收区域可以再生åQŒæ¶ˆé™¤æš‚停是òq¶è¡Œçš„,所有可用的CPU都会(x¨¬)参加åQŒå¤§å¤šæ•°æ¶ˆé™¤æš‚停攉™›†å¯ç”¨çš„å¹´è½ÕdŒºåŸŸï¼Œå’Œå…¶å®ƒHotSpot GC中的òq´è½»å›žæ”¶æ˜¯ä¸€æ ïL(f¨¥ng)š„åQŒåœ¨æš‚停期间偶尔也会(x¨¬)选择òq´è€åŒºåŸŸå›žæ”Óž¼Œå› äØ“(f¨´)G1在年è½ÖM¸€ä»£å›žæ”¶ä¸Š˜q˜è‚©è´Ÿäº†(ji¨£n)òq´è€ä»£çš„回收活动ã€?/div><div></div><div>å’ŒCMS相同的是åQŒG1ä¼?x¨¬)å®šæœŸæ‰§è¡Œä¸€ä¸ªåÆˆå‘æ ‡è®°æš‚åœï¼Œ˜q™ä¸ªé˜¶æ®µçš„ä¸»è¦èŒè´£æ˜¯è¯†åˆ«å“ªä¸€ä¸ªå¹´è€åŒºåŸŸçš„åžƒåœ¾å¯¹è±¡æ˜¯æœ€å®Œæ•´çš„ï¼Œå› äØ“(f¨´)˜q™äº›æ˜¯æœ€æœ‰æ•ˆå’Œæœ€å€¼å¾—回收的,和CMS不同的是åQŒG1不会(x¨¬)执行òq¶å‘清除暂停åQŒç›¸åï¼Œæœ€æœ‰ç”¨çš„年老区域是通过òq¶å‘标记暂停标识的,在随后的消除暂停期间˜q›è¡Œå›žæ”¶ã€?/div><div></div><div>使用G1</div><div></div><div>G1仍然被看做是试验品,可以使用下面两个参数开启它åQ?/div><div></div><div>-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC </div><div>ä¸ÞZº†(ji¨£n)讄¡½®ä¸€ä¸ªGC暂停旉™—´ç›®æ ‡åQŒä‹É用下面的参数åQ?/div><div></div><div>-XX:MaxGCPauseMillis =50  (暂停旉™—´ç›®æ ‡50ms) </div><div>使用G1时还可以指定旉™—´é—´éš”åQŒå½“GC暂停持箋旉™—´æ²¡æœ‰ä¸Šé¢¾l™å‡ºçš„æ—¶é—´é•¿æ—¶å¯ä»¥è¿™ä¹ˆç”¨åQ?/div><div></div><div>-XX:GCPauseIntervalMillis =200  (暂停间隔目标200ms) </div><div>注意上面两个选项表示的目标,没有承诺和保证,在某些情况下它们可能能够工作åQŒGC不是æ€ÀL˜¯èƒ½å¤Ÿæ‰§è¡Œå®ƒä»¬ã€?/div><div></div><div>另外åQŒå¹´è½ÖM»£çš„大ž®å¯ä»¥æ˜Ž¼‹®æŒ‡å®šåª„(ji¨£ng)响消除暂停时é—ß_(d¨¢)¼š(x¨¬)</div><div></div><div>-XX:+G1YoungGenSize=512m (òq´è½»ä»£å¤§ž®?12M) </div><div>G1也ä‹É用幸存空é—ß_(d¨¢)¼ˆå¯èƒ½æ˜¯éž˜qžç®‹çš„区域)(j¨ª)åQŒå®ƒä»¬çš„大小可以使用一个常见的参数指定åQŒå¦‚åQ?/div><div></div><div>-XX:SurvivorRatio=6 </div><div>最后,ä¸ÞZº†(ji¨£n)˜qè¡ŒG1充分发挥其潜力,ž®è¯•讄¡½®ä»¥ä¸‹ä¸¤ä¸ªé»˜è®¤è¢«ç¦ç”¨äº†(ji¨£n)的参敎ͼŒå› äØ“(f¨´)它们可能ä¼?x¨¬)暴露一个罕见的竞争状态:(x¨¬)</div><div></div><div>-XX:+G1ParallelRSetUpdatingEnabled  </div><div> </div><div>-XX:+G1ParallelRSetScanningEnabled  </div><div>注意当设¾|®äº†(ji¨£n)-XX:+PrintGCDetails后,G1比è“v其它HotSpot GCè¦å•°å—¦å¾—å¤šï¼Œå› äØ“(f¨´)它会(x¨¬)打印每个GC¾U¿ç¨‹çš„计时和其它有助于进行故障排除的信息åQŒå¦‚果你想ä‹ÉGC日志更简单,请ä‹Éç”?verbosegc参数ã€?/div><div></div><div>Java 7 G1最新进å±?/div><div></div><div>G1开发现在主要集中在遗留的可靠性问题和改善性能åQŒåŒæ—¶ä¹Ÿåœ¨é€æ­¥¿U»é™¤ä¸‹é¢çš„限åˆÓž¼š(x¨¬)</div><div></div><div>◆G1不能完全支持JVM工具接口åQˆJVM TIåQ‰æˆ–Java½Ž¡ç†æ‰©å±•åQˆJMXåQ‰ï¼Œå› æ­¤å…³äºŽG1的监视和½Ž¡ç†å·¥å…·å¾ˆå¯èƒ½ä¸èƒ½æ­£å¸¸å·¥ä½œï¼›</div><div></div><div>◆G1不支持增量永久性代回收åQŒå¦‚果一个应用程序äñ”生了(ji¨£n)许多¾c»è{储,需要永久性代回收åQŒè¿™åœ¨å®Œæ•´GC期间是可以实现的åQ?/div><div></div><div>◆从GC暂停旉™—´æ¥è¯´åQŒG1有时表现比CMS好有时比CMSå·®ã€?/div><div></div><div>原文åQšJava HotSpot Garbage Collection</div><img src ="http://www.aygfsteel.com/stevenjohn/aggbug/423325.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/stevenjohn/" target="_blank">abin</a> 2015-03-09 20:15 <a href="http://www.aygfsteel.com/stevenjohn/archive/2015/03/09/423325.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jvm垃圾回收http://www.aygfsteel.com/stevenjohn/archive/2014/12/24/421801.htmlabinabinWed, 24 Dec 2014 15:41:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2014/12/24/421801.htmlhttp://www.aygfsteel.com/stevenjohn/comments/421801.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2014/12/24/421801.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/421801.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/421801.html    在jvm中堆½Iºé—´åˆ’分ä¸ÞZ¸‰ä¸ªä»£åQšå¹´è½ÖM»£åQˆYoung GenerationåQ‰ã€å¹´è€ä»£åQˆOld GenerationåQ‰å’Œæ°æ€¹…代(Permanent GenerationåQ‰ã€‚å¹´è½ÖM»£å’Œå¹´è€ä»£æ˜¯å­˜å‚¨åŠ¨æ€äñ”生的对象。永久带主要是存储的是java的类信息åQŒåŒ…括解析得到的æ–ÒŽ(gu¨©)³•、属性、字ŒD늭‰½{‰ã€‚永久带基本不参与垃圑֛žæ”¶ã€‚我们这里讨论的垃圾回收主要是针对年è½ÖM»£å’Œå¹´è€ä»£ã€‚具体如下图ã€?br />


òq´è½»ä»£åˆåˆ†æˆ3个部分,一个eden区和两个相同的survior区。刚开始创建的对象都是攄¡½®åœ¨eden区的。分成这æ ?ä¸ªéƒ¨åˆ†ï¼Œä¸»è¦æ˜¯äØ“(f¨´)äº?ji¨£n)生命周期短的对象尽量留在年è½Õd¸¦ã€‚当eden区申请不到空间的时候,˜q›è¡ŒminorGCåQŒæŠŠå­˜æ´»çš„对象拷贝到survior。年老代主要存放生命周期比较长的对象åQŒæ¯”如缓存对象。具体jvm内存回收˜q‡ç¨‹æè¿°å¦‚下åQˆå¯ä»¥ç»“合上图)(j¨ª)åQ?/p>

1、对象在Eden区完成内存分é…?br />2、当Eden区满äº?ji¨£n),再创建对象,会(x¨¬)因为申请不到空é—ß_(d¨¢)¼Œè§¦å‘minorGCåQŒè¿›è¡Œyoung(eden+1survivor)区的垃圾回收
3、minorGCæ—Óž¼ŒEden不能被回收的对象被放入到½Iºçš„survivoråQˆEden肯定ä¼?x¨¬)被清空åQ‰ï¼Œå¦ä¸€ä¸ªsurvivor里不能被GC回收的对象也ä¼?x¨¬)被攑օ¥˜q™ä¸ªsurvivoråQŒå§‹¾lˆä¿è¯ä¸€ä¸ªsurvivor是空çš?br />4、当做第3步的时候,如果发现survivor满了(ji¨£n)åQŒåˆ™˜q™äº›å¯¹è±¡è¢«copy到old区,或者survivoròq¶æ²¡æœ‰æ»¡åQŒä½†æ˜¯æœ‰äº›å¯¹è±¡å·²¾lèƒö够OldåQŒä¹Ÿè¢«æ”¾å…¥OldåŒ?nbsp;XX:MaxTenuringThreshold
5、当OldåŒø™¢«æ”¾æ»¡çš„之后,˜q›è¡ŒfullGC

在知道垃圑֛žæ”¶æœºåˆ¶ä»¥åŽï¼Œå¤§å®¶å¯ä»¥åœ¨å¯¹jvm中堆的各个参数进行优化设¾|®ï¼Œæ¥æé«˜æ€§èƒ½ã€?/p>









]]>
JVM中的直接引用和符号引ç”?/title><link>http://www.aygfsteel.com/stevenjohn/archive/2014/12/16/421482.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Tue, 16 Dec 2014 12:14:00 GMT</pubDate><guid>http://www.aygfsteel.com/stevenjohn/archive/2014/12/16/421482.html</guid><wfw:comment>http://www.aygfsteel.com/stevenjohn/comments/421482.html</wfw:comment><comments>http://www.aygfsteel.com/stevenjohn/archive/2014/12/16/421482.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/stevenjohn/comments/commentRss/421482.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/stevenjohn/services/trackbacks/421482.html</trackback:ping><description><![CDATA[<p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">JVM在装载classæ–‡äšg的时候,ä¼?x¨¬)有一步是ž®†ç¬¦å·å¼•ç”¨è§£æžäØ“(f¨´)直接引用的过½E‹ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">那么˜q™é‡Œçš?span style="color: #cc0000;">直接引用到底是什么呢åQ?/span></span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">对于指向“¾cÕdž‹”【Class对象】、类变量、类æ–ÒŽ(gu¨©)³•的直接引用可能是<span style="background-color: #ffccff;">指向æ–ÒŽ(gu¨©)³•区的本地指针</span>ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';"><span style="background-color: #ccccff;">指向实例变量、实例方法的直接引用都是偏移é‡?/span>ã€?span style="background-color: #ffccff;">实例变量的直接引用可能是从对象的映像开始算起到˜q™ä¸ªå®žä¾‹å˜é‡ä½ç½®çš„偏¿U»é‡</span>ã€?span style="background-color: #ffccff;">实例æ–ÒŽ(gu¨©)³•的直接引用可能是æ–ÒŽ(gu¨©)³•表的偏移é‡?/span>ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">在《深入java虚拟机》书的第197™å‰|ˆ‘们可以看刎ͼŒå­ç±»ä¸­æ–¹æ³•表的偏¿U»é‡å’Œçˆ¶¾cÖM¸­çš„æ–¹æ³•表的偏¿U»é‡æ˜¯ä¸€è‡´çš„。比如说父类中有一个say()æ–ÒŽ(gu¨©)³•的偏¿U»é‡æ˜?åQŒé‚£ä¹ˆå­¾cÖM¸­sayæ–ÒŽ(gu¨©)³•的偏¿U»é‡ä¹Ÿæ˜¯7ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">书中½W?99™åµè¯´åQŒé€šè¿‡“接口引用”来调用一个方法,jvmå¿…é¡»<span style="background-color: #ffccff;">搜烦(ch¨³)对象的类的方法表</span>才能扑ֈ°ä¸€ä¸ªåˆé€‚çš„æ–ÒŽ(gu¨©)³•。这是因ä¸?span style="background-color: #ffccff;">实现同一个接口的˜q™äº›¾cÖM¸­åQŒä¸ä¸€å®šæ‰€æœ‰çš„æŽ¥å£ä¸­çš„æ–ÒŽ(gu¨©)³•在类æ–ÒŽ(gu¨©)³•åŒÞZ¸­çš„偏¿U»é‡éƒ½æ˜¯ä¸€æ ïL(f¨¥ng)š„</span>。他们有可能ä¼?x¨¬)不一栗÷€‚è¿™æ ïL(f¨¥ng)š„话可能就要搜索方法表才能¼‹®è®¤è¦è°ƒç”¨çš„æ–ÒŽ(gu¨©)³•在哪里ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">而通过“¾cÕd¼•ç”?#8221;来调用一个方法的时候,直接通过偏移量就可以扑ֈ°è¦è°ƒç”¨çš„æ–ÒŽ(gu¨©)³•的位¾|®äº†(ji¨£n)。【因为子¾cÖM¸­çš„æ–¹æ³•的偏移量跟父类中的偏移量是一致的ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei'; background-color: #339999;">所以,通过接口引用调用æ–ÒŽ(gu¨©)³•ä¼?x¨¬)比¾cÕd¼•用慢一些ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">下面介绍下什么是接口引用ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">interface A{void say();}</span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">class B implements A{}</span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">class C{public static void main(String []s){A a=new B();a.say()}}</span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">在上面的½W¬ä¸‰è¡Œä»£ç ä¸­åQŒå°±æ˜¯ç”¨“接口引用”来调用方法ã€?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">--------------------------------------------------------------------</span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei'; color: #cc0000;">½W¦å·å¼•用åQ?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">½W¦å·å¼•用是一个字½W¦ä¸²åQŒå®ƒ¾l™å‡ºäº?ji¨£n)被引用的内容的名字òq¶ä¸”可能ä¼?x¨¬)包含一些其他关于这个被引用™å¹çš„信息——˜q™äº›ä¿¡æ¯å¿…é¡»­‘³ä»¥å”¯ä¸€çš„识别一个类、字ŒDüc(di¨£n)€æ–¹æ³•ã€‚è¿™æ øP¼Œå¯¹äºŽå…¶ä»–¾cȝš„½W¦å·å¼•用必须¾l™å‡º¾cȝš„全名。对于其他类的字ŒDµï¼Œå¿…é¡»¾l™å‡º¾cÕdã€å­—ŒDµåä»¥åŠ(qi¨¢ng)字段描述½W¦ã€‚对于其他类的方法的引用必须¾l™å‡º¾cÕdã€æ–¹æ³•名以及(qi¨¢ng)æ–ÒŽ(gu¨©)³•的描˜q°ç¬¦ã€?br /><br /><br /><br /></span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">æ€È»“åQšJVM对于直接引用和符号引用的处理是有区别的,可以看到½W¦å·å¼•用æ—Óž¼ŒJVMž®†ä‹É用StringBuilder来完成字½W¦ä¸²çš?nbsp; æ·ÕdŠ åQŒè€Œç›´æŽ¥å¼•用时则直接ä‹É用String来完æˆ?直接引用永远比符号引用效率更快,但实际应用开发中不可能全用直接引用,要提高效能可以考虑按虚拟机的思维来编写你的程序ã€?/p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">1.0 直接引用åQ?/p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">public class StringAndStringBuilder{<br />   public static void main(String[] args){    <br />       System.out.println ("s=" + "asdfa");<br />   }<br />}</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">反编译后的:(x¨¬)</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">F:\java\res\字节ç ?gt;javap -c StringAndStringBuilder<br />Compiled from "StringAndStringBuilder.java"<br />public class StringAndStringBuilder extends java.lang.Object{<br />public StringAndStringBuilder();<br />  Code:<br />   0:   aload_0<br />   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V<br />   4:   return</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">public static void main(java.lang.String[]);<br />  Code:<br />   0:   ldc     #2; //String asdfa<br />   2:   astore_1<br />   3:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;<br />   6:   ldc     #4; //String s=asdfa<br />   8:   invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/Str<br />ing;)V<br />   11:  return</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">}</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;"> </p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">2.0 ½W¦å·å¼•用åQ?/p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">public class StringAndStringBuilder{<br />   public static void main(String[] args){    <br />      String s="asdfa";<br />        System.out.println ("s=" + s);<br />   }<br />}</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">反编译后的:(x¨¬)</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">F:\java\res\字节ç ?gt;javap -c StringAndStringBuilder<br />Compiled from "StringAndStringBuilder.java"<br />public class StringAndStringBuilder extends java.lang.Object{<br />public StringAndStringBuilder();<br />  Code:<br />   0:   aload_0<br />   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V<br />   4:   return</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">public static void main(java.lang.String[]);<br />  Code:<br />   0:   ldc     #2; //String asdfa<br />   2:   astore_1<br />   3:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;<br />   6:   new     #4; //class java/lang/StringBuilder<br />   9:   dup<br />   10:  invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V<br />   13:  ldc     #6; //String s=<br />   15:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/<br />String;)Ljava/lang/StringBuilder;<br />   18:  aload_1<br />   19:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/<br />String;)Ljava/lang/StringBuilder;<br />   22:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/la<br />ng/String;<br />   25:  invokevirtual   #9; //Method java/io/PrintStream.println:(Ljava/lang/Str<br />ing;)V<br />   28:  return</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #ffffff;">}</p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';"><br /></span></p><img src ="http://www.aygfsteel.com/stevenjohn/aggbug/421482.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/stevenjohn/" target="_blank">abin</a> 2014-12-16 20:14 <a href="http://www.aygfsteel.com/stevenjohn/archive/2014/12/16/421482.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> java.lang.OutOfMemoryError: unable to create new native threadhttp://www.aygfsteel.com/stevenjohn/archive/2014/12/15/421402.htmlabinabinMon, 15 Dec 2014 04:08:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2014/12/15/421402.htmlhttp://www.aygfsteel.com/stevenjohn/comments/421402.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2014/12/15/421402.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/421402.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/421402.html java.lang.OutOfMemoryError: unable to create new native thread
引发此问题的原因有两个:(x¨¬)

1.¾U¿ç¨‹æ•°è¶…˜q‡äº†(ji¨£n)操作¾pȝ»Ÿçš„限制ã€?br />
* ä½¿ç”¨top命ä×o(h¨´)查看¾pȝ»Ÿèµ„源åQŒå¦‚果发现剩余内存很多,而又出现此异常,则基本可以肯定是ç”׃ºŽæ“ä½œ¾pȝ»Ÿ¾U¿ç¨‹æ•°é™åˆ¶å¼•èµïL(f¨¥ng)š„ã€?br />
[root@jack ~]# top
top - 11:36:52 up 5 days,  1:34,  4 users,  load average: 0.00, 0.00, 0.07
Tasks: 131 total,   1 running, 130 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.2%us,  0.2%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   3821320k total,  3122236k used,   699084k free,   112636k buffers
Swap:  6062072k total,   571760k used,  5490312k free,   840728k cached


* åœ¨linux下,可以通过 ulimit -a æŸ¥çœ‹¾pȝ»Ÿé™åˆ¶

[root@jack ~]# 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) 29644
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) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

max user process即系¾lŸå¯åˆ›å¾æœ€å¤§çº¿½E‹æ•°ã€?br />
* å¯ä»¥ä½¿ç”¨ ulimit -u 4096 ä¿®æ”¹max user processesçš„å€û|¼Œä½†æ˜¯åªèƒ½åœ¨å½“前终端的˜q™ä¸ªsession里面生效åQŒé‡æ–°ç™»å½•后仍然是ä‹É用系¾lŸé»˜è®¤å€¹{€?br />
正确的修æ”ÒŽ(gu¨©)–¹å¼æ˜¯ä¿®æ”¹/etc/security/limits.d/90-nproc.confæ–‡äšg中的倹{€?br />

[root@jack ~]# cat /etc/security/limits.d/90-nproc.conf
# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.

*          soft    nproc     1024

2.¾pȝ»Ÿå†…存不èƒö
如果通过top命ä×o(h¨´)¼‹®è®¤åˆ°æ˜¯å†…存不èƒöåQŒåˆ™å¯ä»¥é€šè¿‡java启动参数 -Xss修改每个¾U¿ç¨‹æ ˆå¤§ž®ã€‚减ž®æ­¤å‚æ•°åQŒå¯ä»¥æé«˜æœ€å¤§çº¿½E‹æ•°ã€‚当ç„?d¨°ng)ž¼Œè¦ä¿è¯ä½ çš„线½E‹ä‹É用的内存不会(x¨¬)­‘…过˜q™ä¸ªæ•°ã€?br />
当然åQŒå¦‚果不是因为系¾lŸçñ”别的问题åQŒé‚£ž®Þqš„优化½E‹åºäº?ji¨£n),‹‚€(g¨¨)查有没有泄露的内存,有没有业务逻辑存在大量òq¶å‘½{‰ç­‰ã€?br />

]]>
ä¸ÞZ»€ä¹ˆæ–°ç”Ÿä»£æœ‰ä¸¤ä¸ªsurvivor?http://www.aygfsteel.com/stevenjohn/archive/2014/12/09/421217.htmlabinabinTue, 09 Dec 2014 06:16:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2014/12/09/421217.htmlhttp://www.aygfsteel.com/stevenjohn/comments/421217.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2014/12/09/421217.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/421217.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/421217.html StackOverflow上面¾l™å‡ºçš„解释是åQ?/p>

The reason for the HotSpot JVM's two survivor spaces is to reduce the need to deal with fragmentation. New objects are allocated in eden space. All well and good. When that's full, you need a GC, so kill stale objects and move live ones to a survivor space, where they can mature for a while before being promoted to the old generation. Still good so far. The next time we run out of eden space, though, we have a conundrum. The next GC comes along and clears out some space in both eden and our survivor space, but the spaces aren't contiguous. So is it better to

  1. Try to fit the survivors from eden into the holes in the survivor space that were cleared by the GC?
  2. Shift all the objects in the survivor space down to eliminate the fragmentation, and then move the survivors into it?
  3. Just say "screw it, we're moving everything around anyway," and copy all of the survivors from both spaces into a completely separate space--the second survivor space--thus leaving you with a clean eden and survivor space where you can repeat the sequence on the next GC?

Sun's answer to the question is obvious.


  对于如何辑ֈ°“无碎ç‰?#8221;的目的,理解上可能有些困难,下面我把新生代回收机制详¾l†è§£é‡Šä¸€ä¸‹ï¼š(x¨¬)

  注意åQ?span style="color: #ff0000;">两个survivor是交替ä‹É用的åQŒåœ¨ä»ÀL„ä¸€ä¸ªæ—¶åˆ»ï¼Œå¿…定有一个survivor为空åQŒä¸€ä¸ªsurvivor中存攄¡€å¯¹è±¡åQˆè¿ž¾l­å­˜æ”¾ï¼Œæ— ç¢Žç‰‡ï¼‰(j¨ª)。回收过½E‹å¦‚下:(x¨¬)

  S1、GCåQŒå°†eden中的live对象攑օ¥å½“å‰ä¸äØ“(f¨´)½Iºçš„survivor中,ž®†eden中的非live对象回收。如果survivor满了(ji¨£n)åQŒä¸‹‹Æ¡å›žæ”¶æ‰§è¡ŒS2åQ›å¦‚æžœsurvivor未满åQŒä¸‹‹Æ¡å›žæ”¶ä»ç„¶ä»¥S1的方式回æ”Óž¼›

  S2、GCåQŒå°†eden和存攄¡€å¯¹è±¡çš„survivor中的live对象攑օ¥å½“前为空的survivor中,ž®†éžlive对象回收ã€?/p>

  可以看到åQŒä¸Š˜q°çš„æ–°ç”Ÿä»£å›žæ”¶æœºåˆ¶ä¿è¯äº†(ji¨£n)一个survivor为空åQŒå¦ä¸€ä¸ªéž½Iºsurvivor中无¼„Žç‰‡ã€?/p>

  在执行一定次数的minor GC后,ä¼?x¨¬)通过Full GCž®†æ–°ç”Ÿä»£çš„survivor中的对象¿UÕd…¥è€å¹´ä»£ã€?/p>


  对于理解GC的整个机åˆÓž¼ŒæŽ¨èä¸€½‹‡éžå¸¸å¥½çš„æ–‡ç«?/span>åQ?a target="_blank" style="color: #ca0000; text-decoration: none;">http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/



]]>
Java 新生代、年è½ÖM»£ã€è€å¹´ä»?/title><link>http://www.aygfsteel.com/stevenjohn/archive/2013/09/07/403790.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Sat, 07 Sep 2013 11:09:00 GMT</pubDate><guid>http://www.aygfsteel.com/stevenjohn/archive/2013/09/07/403790.html</guid><wfw:comment>http://www.aygfsteel.com/stevenjohn/comments/403790.html</wfw:comment><comments>http://www.aygfsteel.com/stevenjohn/archive/2013/09/07/403790.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/stevenjohn/comments/commentRss/403790.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/stevenjohn/services/trackbacks/403790.html</trackback:ping><description><![CDATA[<!--StartFragment --> <div>òq´é’ä»?新生代(eden spaceåQ?2个survivor<br />òq´é’代用来存放新˜q‘创建的对象åQŒå°ºå¯”Ršå †å¤§ž®çš„增大和减ž®è€Œç›¸åº”的变化åQŒé»˜è®¤å€¼æ˜¯ä¿æŒä¸ºå †å¤§å°çš?/15åQŒå¯ä»¥é€šè¿‡-Xmn参数讄¡½®òq´é’代䨓(f¨´)固定大小åQŒä¹Ÿå¯ä»¥é€šè¿‡-XX:NewRatio来设¾|®å¹´é’代与年老代的大ž®æ¯”例,òq´é’代的特点是对象更新速度快,在短旉™—´å†…äñ”生大量的“æ­ÖMº¡å¯¹è±¡”ã€?br />òq´è½»ä»£çš„特点是äñ”生大量的æ­ÖMº¡å¯¹è±¡,òq¶ä¸”要是产生˜qžç®‹å¯ç”¨çš„空é—? æ‰€ä»¥ä‹É用复制清除算法和òq¶è¡Œæ”‰™›†å™¨è¿›è¡Œåžƒåœ‘Ö›žæ”?     å¯¹å¹´è½ÖM»£çš„垃圑֛žæ”¶ç§°ä½œåˆ¾U§å›žæ”?nbsp;(minor gc)<br /><br />初çñ”回收ž®†å¹´è½ÖM»£åˆ†äØ“(f¨´)三个区域,  ä¸€ä¸ªæ–°ç”Ÿä»£ , 2个大ž®ç›¸åŒçš„复活ä»?  åº”用½E‹åºåªèƒ½ä½¿ç”¨ä¸€ä¸ªæ–°ç”Ÿä»£å’Œä¸€ä¸ªå¤‹zÖM»£, å½“发生初¾U§åžƒåœ‘Ö›žæ”¶çš„æ—¶å€?gc挂è“v½E‹åº, ç„¶åŽž®†æ–°ç”Ÿä»£å’Œå¤‹zÖM»£ä¸­çš„存活对象复制到另外一个非‹zÕdŠ¨çš„å¤‹zÖM»£ä¸?然后一‹Æ¡æ€§æ¸…除新生代和复‹zÖM»£,ž®†åŽŸæ¥çš„éžå¤‹zÖM»£æ ‡è®°æˆäØ“(f¨´)‹zÕdŠ¨å¤æ´»ä»?    ž®†åœ¨æŒ‡å®š‹Æ¡æ•°å›žæ”¶åŽä»ç„¶å­˜åœ¨çš„对象¿UÕdŠ¨åˆ°å¹´è€ä»£ä¸? åˆçñ”回收å?得到一个空的可用的新生ä»?<br /></div><img src ="http://www.aygfsteel.com/stevenjohn/aggbug/403790.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/stevenjohn/" target="_blank">abin</a> 2013-09-07 19:09 <a href="http://www.aygfsteel.com/stevenjohn/archive/2013/09/07/403790.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM中类加蝲™åºåºå?qi¨¢ng)classpath½Ž€ä»?/title><link>http://www.aygfsteel.com/stevenjohn/archive/2013/09/07/403787.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Sat, 07 Sep 2013 07:43:00 GMT</pubDate><guid>http://www.aygfsteel.com/stevenjohn/archive/2013/09/07/403787.html</guid><wfw:comment>http://www.aygfsteel.com/stevenjohn/comments/403787.html</wfw:comment><comments>http://www.aygfsteel.com/stevenjohn/archive/2013/09/07/403787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/stevenjohn/comments/commentRss/403787.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/stevenjohn/services/trackbacks/403787.html</trackback:ping><description><![CDATA[<div>昨天åQŒçœ‹ä¸€ä¸ªbuild Standalone中databrusher的一个脚本,发现一个Java¾cÖM¼¼ä¹Žæ²¡æœ‰åœ¨classpath中,好像也可一直运行了(ji¨£n)。很疑惑åQŒé—®äº?ji¨£n)对应的开发同学,然后自己好好看了(ji¨£n)下它的代码,才知道了(ji¨£n)原理ã€?/div><div>命ä×o(h¨´)是:(x¨¬)$JAVA_HOME/bin/java $JAVA_OPTS com.alibaba.standalone.AppStartor com.alibaba.intl.standalone.databrusher.Startor "$main_class" "$signal_file" "$recivers"</div><div>原理是:(x¨¬)Javaæ ÒŽ(gu¨©)®classpath扑ֈ°åQŒcom.alibaba.standalone.AppStartor˜q™ä¸ªclassåQŒè¿è¡Œè¿™ä¸ªclassåQŒä¼š(x¨¬)启动一个classloader来加载com.alibaba.intl.standalone.databrusher.StartoråQˆåœ¨é‡Œé¢ä¼?x¨¬)指定到WORLDS-INF目录下加载类åQ‰ï¼Œç„¶åŽcom.alibaba.intl.standalone.databrusher.Startorä¼?x¨¬)启动对应çš?$main_class".</div><div>然后åQŒèбäº?ji¨£n)挺多时间好好看了(ji¨£n)一下Javaçš„classloaderåQŒäº†(ji¨£n)解一下其中的原理和看äº?ji¨£n)下代码。下面也½Ž€å•æ€È»“一下吧ã€?/div><div>java虚拟机是由sun.misc.Launcher来初始化çš?也就是java(或java.exe)˜q™ä¸ª½E‹åºæ¥åšçš?虚拟机按以下™åºåºæœçƒ¦(ch¨³)òq¶è£…载所有需要的¾c?</div><div>  1,引导¾c?¾l„成javaòq›_°çš„ç±»,包含rt.jarå’Œi18n.jar½{‰åŸº¼‹€jar包中的类.</div><div>  2,扩展¾c?使用java扩展机制的类,都是位于扩展目录($JAVA_HOME/jre/lib/ext)中的.jar档案åŒ?</div><div>  3,用户¾c?开发者定义的¾cÀLˆ–者没有ä‹É用java扩展机制的第三方产品.ä½ å¿…™åÕdœ¨å‘½ä×o(h¨´)行中使用-classpath选项或者ä‹É用CLASSPATH环境变量来确定这些类的位åQŒæˆ–者自己写C(j¨©)lassLoader加蝲ã€?/div><div></div><div>Javaçš„class loader的大致情况如下图所½Cºï¼š(x¨¬)</div><div>http://renyongjie668.blog.163.com/prevPhDownload.do?host=renyongjie668&albumId=197449439&photoId=6568564371</div><div>bootstrap classloader -->extension classloader-->system classloader</div><div>虚拟æœÞZ¸€å¯åЍåQŒä¼š(x¨¬)先做一些初始化的动作。一旦初始化动作完成之后åQŒå°±ä¼?产生½W¬ä¸€ä¸ªç±»åˆ«åŠ è½½å™¨åQŒå³æ‰€è°“çš„Bootstrap LoaderåQŒBootstrap Loader 是由C++ 所撰写而成åQŒè¿™ä¸ªBootstrap Loader所做的初始工作中,除了(ji¨£n)也做一些基本的初始化动作之外,最重要的就是加载定义在sun.misc 命名½Iºé—´åº•下的Launcher.java 之中的ExtClassLoader( 因䨓(f¨´)是inner class åQŒæ‰€ä»¥ç¼–译之后会(x¨¬)变成Launcher$ExtClassLoader.class) åQŒåƈ讑֮šå…¶Parent 为nullåQŒä»£è¡¨å…¶çˆ¶åŠ è½½å™¨ä¸ºBootstrap Loader 。然后Bootstrap Loader ,再要求加载定义于sun.misc 命名½Iºé—´åº•下的Launcher.java 之中的AppClassLoader( 因䨓(f¨´)是inner classåQŒæ‰€ä»¥ç¼–译之后会(x¨¬)变成Launcher$AppClassLoader.class) åQŒåƈ讑֮šå…¶Parent ä¸ÞZ¹‹å‰äñ”生的ExtClassLoader 实例ã€?/div><div>a. Bootstrap ClassLoader/启动¾cÕdŠ è½½å™¨</div><div>主要负责java_home/jre/lib目录下的核心(j¨©) api æˆ?-Xbootclasspath 选项指定的jar包装入工ä½?</div><div>b. Extension ClassLoader/扩展¾cÕdŠ è½½å™¨</div><div>主要负责java_home/jre/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工ä½?/div><div>c. System ClassLoader/¾pȝ»Ÿ¾cÕdŠ è½½å™¨</div><div>主要负责java -classpath/-Djava.class.pathæˆ?CLASSPATH变量所指的目录下的¾cÖM¸Žjar包装入工ä½?(˜q™é‡Œéœ€è¦è¯´æ˜Žçš„æ˜¯ï¼Œå¦‚æžœ$CLASSPATH为空åQŒjdkä¼?x¨¬)默认将被运行的Java¾cȝš„å½“å‰è·¯å¾„ä½œäØ“(f¨´)一个默认的$CLASSPATHåQŒä¸€ä½†è®¾¾|®äº†(ji¨£n)$CLASSPATH变量åQŒåˆ™ä¼?x¨¬)åˆ?CLASSPATH对应的èµ\径下åŽÕd¯»æ‰„¡›¸åº”çš„¾c»ï¼Œæ‰¾ä¸åˆ°å°±ä¼?x¨¬)报错。这个结论,我已¾lç»˜q‡æµ‹è¯•,òq¶ä¸”看了(ji¨£n)下类加蝲器中源代码)(j¨ª)</div><div>d. User Custom ClassLoader/用户自定义类加蝲¾c?java.lang.ClassLoader的子¾c?在程序运行期é—? 通过java.lang.ClassLoader的子¾cÕdŠ¨æ€åŠ è½½classæ–‡äšg, 体现java动态实时类装入ç‰ÒŽ(gu¨©)€?</div><div></div><div>ä¸ÞZº†(ji¨£n)有更多的äº?ji¨£n)è§£åQŒå†™äº?ji¨£n)个½Ž€å•çš„Java½E‹åºå¯¹å‰é¢ä¸‰¿Uclassloader能加载类的èµ\径及(qi¨¢ng)å…¶parent¾c»è¿›è¡Œäº†(ji¨£n)‹¹‹è¯•。代码如下:(x¨¬)<br /><div>import java.net.URL;</div><div>import java.net.URLClassLoader;</div><div></div><div> /**</div><div> * @className: IClassLoader</div><div> * @description: ‹¹‹è¯•三种classloader加蝲¾cȝš„路径åQŒåŠ(qi¨¢ng)å…¶parent</div><div> * @author: ½W‘遍世界</div><div> * @createTime: 2010-11-17 下午07:33:40</div><div> */</div><div>public class IClassLoader {</div><div>    public static void main(String[] args) {</div><div>//        ‹¹‹è¯•bootstrap classloader 的类加蝲路径</div><div>        URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();</div><div>        for (int i = 0; i < urls.length; i++) {</div><div>          System.out.println(urls[i].toExternalForm());</div><div>        }</div><div>       </div><div>//        ‹¹‹è¯•extension classloader 的类加蝲路径åQŒå…ˆæ‰“印一个èµ\径,再打印出其parentåQŒç„¶åŽå†æ‰“印出类加蝲路径中的所有jaråŒ?/div><div>        System.out.println("-------------------------------------");</div><div>        System.out.println(System.getProperty("java.ext.dirs"));</div><div>        ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();</div><div>        System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());</div><div>        System.out.println("extension classloader can use thess jars:");</div><div>        URL[] extURLs = ((URLClassLoader)ClassLoader.getSystemClassLoader().getParent()).getURLs();</div><div>        for (int i = 0; i < extURLs.length; i++) {</div><div>               System.out.println(extURLs[i]);</div><div>        }       </div><div>       </div><div>//      ‹¹‹è¯•system classloader 的类加蝲路径åQŒå…¶å®žä¹Ÿž®±æ—¶classpathçš„èµ\径,òq¶æ‰“印出它的parent</div><div>        System.out.println("-------------------------------------");</div><div>        System.out.println(System.getProperty("java.class.path"));</div><div>        System.out.println(ClassLoader.getSystemResource(""));</div><div>        ClassLoader systemClassloader=ClassLoader.getSystemClassLoader();</div><div>        System.out.println("the parent of system classloader : "+systemClassloader.getParent());</div><div>    }</div><div>}</div><br /><div>本机(linux+jdk1.5)˜qè¡Œ¾l“果如下åQ?/div><div>file:/usr/ali/java/jre/lib/rt.jar</div><div>file:/usr/ali/java/jre/lib/i18n.jar</div><div>file:/usr/ali/java/jre/lib/sunrsasign.jar</div><div>file:/usr/ali/java/jre/lib/jsse.jar</div><div>file:/usr/ali/java/jre/lib/jce.jar</div><div>file:/usr/ali/java/jre/lib/charsets.jar</div><div>file:/usr/ali/java/jre/classes</div><div>-------------------------------------</div><div>/usr/ali/java/jre/lib/ext</div><div>the parent of extension classloader : null</div><div>extension classloader can use thess jars:</div><div>file:/usr/ali/java/jre/lib/ext/emma.jar</div><div>file:/usr/ali/java/jre/lib/ext/localedata.jar</div><div>file:/usr/ali/java/jre/lib/ext/dnsns.jar</div><div>file:/usr/ali/java/jre/lib/ext/sunpkcs11.jar</div><div>file:/usr/ali/java/jre/lib/ext/sunjce_provider.jar</div><div>-------------------------------------</div><div>.:/usr/ali/java/lib/dt.jar:/usr/ali/java/lib/tools.jar</div><div>file:/home/master/workspace/2010_11/bin/</div><div>the parent of system classloader :  sun.misc.Launcher$ExtClassLoader@1a5ab41</div><div></div><div>//ps:当前路径.åÏx˜¯/home/master/workspace/2010_11/bin/</div><br /><br /><br /><div>关于Javaçš„classloader其原理还是需要好好理解才能清楚的åQŒä»…通过一天的äº?ji¨£n)è§£åQŒè®°å½•䨓(f¨´)上面那么多吧。更多详¾l†ä¿¡æ¯ï¼Œå¯ä»¥å‚考如下资料:(x¨¬)</div><div>http://snandy.javaeye.com/blog/307083</div><div>http://haofenglemon.javaeye.com/blog/426382</div><div>http://blog.csdn.net/zdwzzu2006/archive/2008/04/05/2253982.aspx</div><div>http://wuquanyin1011.javaeye.com/blog/703842</div><div>http://hi.baidu.com/yangzhibin_bai/blog/item/78846cce1cb86b0992457ead.html</div><div>http://www.aygfsteel.com/clraychen/archive/2008/02/20/180868.html</div><div></div><br /><br /><br /></div><img src ="http://www.aygfsteel.com/stevenjohn/aggbug/403787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/stevenjohn/" target="_blank">abin</a> 2013-09-07 15:43 <a href="http://www.aygfsteel.com/stevenjohn/archive/2013/09/07/403787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM监控工具介绍jstack, jconsole, jinfo, jmap, jdb, jstathttp://www.aygfsteel.com/stevenjohn/archive/2013/07/26/401991.htmlabinabinFri, 26 Jul 2013 02:48:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2013/07/26/401991.htmlhttp://www.aygfsteel.com/stevenjohn/comments/401991.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2013/07/26/401991.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/401991.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/401991.htmlhttp://blog.csdn.net/kelly859/article/details/5827365

]]>
JVM性能调优 http://www.aygfsteel.com/stevenjohn/archive/2013/05/31/400030.htmlabinabinFri, 31 May 2013 07:49:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2013/05/31/400030.htmlhttp://www.aygfsteel.com/stevenjohn/comments/400030.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2013/05/31/400030.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/400030.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/400030.html最˜q‘å› ™å¹ç›®å­˜åœ¨å†…存泄漏åQŒæ•…˜q›è¡Œå¤§è§„模的JVM性能调优 åQ?/font> 现把¾léªŒåšä¸€è®°å½•ã€?

一、JVM内存模型å?qi¨¢ng)垃圾收集算æ?/p>

 1.æ ÒŽ(gu¨©)®Javaè™šæ‹Ÿæœø™§„范,JVMž®†å†…å­˜åˆ’åˆ†äØ“(f¨´)åQ?/p>

  • NewåQˆå¹´è½ÖM»£åQ?/li>
  • TenuredåQˆå¹´è€ä»£åQ?/li>
  • æ°æ€¹…代(PermåQ?/li>

  其中Newå’ŒTenured属于堆内存,堆内存会(x¨¬)从JVM启动参数åQ?Xmx:3GåQ‰æŒ‡å®šçš„内存中分配,Perm不属于堆内存åQŒæœ‰è™šæ‹Ÿæœºç›´æŽ¥åˆ†é…ï¼Œä½†å¯ä»¥é€šè¿‡-XX:PermSize -XX:MaxPermSize ½{‰å‚数调整其大小ã€?/p>

  • òq´è½»ä»£ï¼ˆNewåQ‰ï¼š(x¨¬)òq´è½»ä»£ç”¨æ¥å­˜æ”¾JVM刚分配的Java对象
  • òq´è€ä»£åQˆTenured)åQšå¹´è½ÖM»£ä¸­ç»˜q‡åžƒåœ‘Ö›žæ”¶æ²¡æœ‰å›žæ”¶æŽ‰çš„对象将被Copy到年老代
  • æ°æ€¹…代(PermåQ‰ï¼š(x¨¬)æ°æ€¹…代存放Class、Method元信息,其大ž®è·Ÿ™å¹ç›®çš„规模、类、方法的量有养I¼Œä¸€èˆ¬è®¾¾|®äØ“(f¨´)128Mž®Þpƒö够,讄¡½®åŽŸåˆ™æ˜¯é¢„ç•?0%的空间ã€?/li>

New又分为几个部分:(x¨¬)

  • EdenåQšEden用来存放JVM刚分配的对象
  • Survivor1
  • Survivro2åQšä¸¤ä¸ªSurvivor½Iºé—´ä¸€æ ·å¤§åQŒå½“Eden中的对象¾lè¿‡åžƒåœ¾å›žæ”¶æ²¡æœ‰è¢«å›žæ”¶æŽ‰æ—Óž¼Œä¼?x¨¬)在两个Survivor之间来回CopyåQŒå½“满èƒö某个条äšgåQŒæ¯”如Copy‹Æ¡æ•°åQŒå°±ä¼?x¨¬)被Copy到Tenured。显ç„?d¨°ng)ž¼ŒSurvivor只是增加äº?ji¨£n)对象在òq´è½»ä»£ä¸­çš„逗留旉™—´åQŒå¢žåŠ äº†(ji¨£n)被垃圑֛žæ”¶çš„可能性ã€?/li>

 2.垃圾回收½Ž—法

  垃圾回收½Ž—æ³•å¯ä»¥åˆ†äØ“(f¨´)三类åQŒéƒ½åŸÞZºŽæ ‡è®°-清除åQˆå¤åˆÓž¼‰(j¨ª)½Ž—法åQ?/p>

  • Serial½Ž—法åQˆå•¾U¿ç¨‹åQ?/li>
  • òq¶è¡Œ½Ž—法
  • òq¶å‘½Ž—法

  JVMä¼?x¨¬)根据机器的¼‹¬äšg配置å¯ÒŽ(gu¨©)¯ä¸ªå†…存代选择适合的回收算法,比如åQŒå¦‚果机器多äº?个核åQŒä¼š(x¨¬)对年è½ÖM»£é€‰æ‹©òq¶è¡Œ½Ž—法åQŒå…³äºŽé€‰æ‹©¾l†èŠ‚è¯·å‚è€ƒJVM调优文档ã€?/p>

  ½Eå¾®è§£é‡Šä¸‹çš„æ˜¯ï¼Œòq¶è¡Œ½Ž—法是用多线½E‹è¿›è¡Œåžƒåœ‘Ö›žæ”Óž¼Œå›žæ”¶æœŸé—´ä¼?x¨¬)暂停程序的执行åQŒè€Œåƈ发算法,也是多线½E‹å›žæ”Óž¼Œä½†æœŸé—´ä¸åœæ­¢åº”用执行。所以,òq¶å‘½Ž—法适用于交互性高的一些程序。经˜q‡è§‚察,òq¶å‘½Ž—法ä¼?x¨¬)减ž®‘å¹´è½ÖM»£çš„大ž®ï¼Œå…¶å®žž®±æ˜¯ä½¿ç”¨äº?ji¨£n)一个大的年老代åQŒè¿™åè¿‡æ¥è·Ÿòq¶è¡Œ½Ž—法相比吞吐量相对较低ã€?/p>

  ˜q˜æœ‰ä¸€ä¸ªé—®é¢˜æ˜¯åQŒåžƒåœ‘Ö›žæ”¶åŠ¨ä½œä½•æ—¶æ‰§è¡Œï¼Ÿ

  • 当年è½ÖM»£å†…存满时åQŒä¼š(x¨¬)引发一‹Æ¡æ™®é€šGCåQŒè¯¥GC仅回收年è½ÖM»£ã€‚需要强调的æ—Óž¼Œòq´è½»ä»£æ»¡æ˜¯æŒ‡Eden代满åQŒSurvivor满不ä¼?x¨¬)引发GC
  • 当年老代满时ä¼?x¨¬)引发Full GCåQŒFull GCž®†ä¼š(x¨¬)同时回收òq´è½»ä»£ã€å¹´è€ä»£
  • 当永久代满时也会(x¨¬)引发Full GCåQŒä¼š(x¨¬)坯D‡´Class、Method元信息的卸蝲

  另一个问题是åQŒä½•时会(x¨¬)抛出OutOfMemoryExceptionåQŒåƈ不是内存被耗空的时候才抛出

  • JVM98%的时间都èŠÞp´¹åœ¨å†…存回æ”?/li>
  • 每次回收的内存小äº?%

  满èƒö˜q™ä¸¤ä¸ªæ¡ä»¶å°†è§¦å‘OutOfMemoryExceptionåQŒè¿™ž®†ä¼š(x¨¬)留给¾pȝ»Ÿä¸€ä¸ªå¾®ž®çš„间隙以做一些Down之前的操作,比如手动打印Heap Dumpã€?/p>

二、内存泄漏及(qi¨¢ng)解决æ–ÒŽ(gu¨©)³•

 1.¾pȝ»Ÿå´©æºƒå‰çš„一些现象:(x¨¬)

    • 每次垃圾回收的时间越来越长,ç”׃¹‹å‰çš„10ms廉™•¿åˆ?0ms左右åQŒFullGC的时间也有之前的0.5s廉™•¿åˆ?ã€?s
    • FullGC的次数越来越多,最频繁旉™š”不到1分钟ž®Þp¿›è¡Œä¸€‹Æ¡FullGC
    • òq´è€ä»£çš„å†…å­˜è¶Šæ¥è¶Šå¤§åÆˆä¸”æ¯‹Æ¡FullGC后年老代没有内存被释æ”?/li>

       ä¹‹åŽ¾pȝ»Ÿä¼?x¨¬)无法响应新的请求,逐渐到达OutOfMemoryErrorçš„äÍ(f¨´)界倹{€?/p>

       2.生成堆的dumpæ–‡äšg

       é€šè¿‡JMXçš„MBean生成当前的Heap信息åQŒå¤§ž®äØ“(f¨´)一ä¸?GåQˆæ•´ä¸ªå †çš„大ž®ï¼‰(j¨ª)çš„hprofæ–‡äšgåQŒå¦‚果没有启动JMX可以通过Javaçš„jmap命ä×o(h¨´)来生成该文äšgã€?/p>

       3.分析dumpæ–‡äšg

       ä¸‹é¢è¦è€ƒè™‘的是如何打开˜q™ä¸ª3G的堆信息文äšgåQŒæ˜¾ç„¶ä¸€èˆ¬çš„Window¾pȝ»Ÿæ²¡æœ‰˜q™ä¹ˆå¤§çš„内存åQŒå¿…™åÕd€ŸåŠ©é«˜é…¾|®çš„Linux。当然我们可以借助X-Window把Linux上的囑ÖŞ导入到Window。我们考虑用下面几¿Uå·¥å…äh‰“开该文ä»Óž¼š(x¨¬)

      1. Visual VM
      2. IBM HeapAnalyzer
      3. JDK 自带的Hprof工具

       ä½¿ç”¨˜q™äº›å·¥å…·æ—¶äØ“(f¨´)äº?ji¨£n)确保加载速度åQŒå¾è®®è®¾¾|®æœ€å¤§å†…å­˜äØ“(f¨´)6G。ä‹É用后发现åQŒè¿™äº›å·¥å…·éƒ½æ— æ³•直观地观察到内存泄漏åQŒVisual VM虽能观察到对象大ž®ï¼Œä½†çœ‹ä¸åˆ°è°ƒç”¨å †æ ˆåQ›HeapAnalyzer虽然能看到调用堆栈,却无法正¼‹®æ‰“开一ä¸?G的文件。因此,我们又选用äº?ji¨£n)Eclipse专门的静(r¨´n)æ€å†…å­˜åˆ†æžå·¥å…øP¼š(x¨¬)Matã€?/p>

       4.分析内存泄漏

       é€šè¿‡Mat我们能清楚地看到åQŒå“ªäº›å¯¹è±¡è¢«æ€€ç–‘䨓(f¨´)内存泄漏åQŒå“ªäº›å¯¹è±¡å çš„空间最大及(qi¨¢ng)对象的调用关¾p…R€‚é’ˆå¯ÒŽ(gu¨©)œ¬æ¡ˆï¼Œåœ¨ThreadLocal中有很多的JbpmContext实例åQŒç»˜q‡è°ƒæŸ¥æ˜¯JBPMçš„Context没有关闭所致ã€?/p>

       å¦ï¼Œé€šè¿‡Mat或JMX我们˜q˜å¯ä»¥åˆ†æžçº¿½E‹çŠ¶æ€ï¼Œå¯ä»¥è§‚å¯Ÿåˆ°çº¿½E‹è¢«é˜Õd¡žåœ¨å“ªä¸ªå¯¹è±¡ä¸ŠåQŒä»Žè€Œåˆ¤æ–­ç³»¾lŸçš„瓉™¢ˆã€?/p>

       5.回归问题

         QåQ?span style="color: #0000ff">ä¸ÞZ»€ä¹ˆå´©æºƒå‰åžƒåœ¾å›žæ”¶çš„æ—¶é—´è¶Šæ¥è¶Šé•¿ï¼Ÿ

         A:æ ÒŽ(gu¨©)®å†…存模型和垃圑֛žæ”¶ç®—法,垃圾回收分两部分åQšå†…存标记、清除(复制åQ‰ï¼Œæ ‡è®°éƒ¨åˆ†åªè¦å†…存大小固定旉™—´æ˜¯ä¸å˜çš„åQŒå˜çš„æ˜¯å¤åˆ¶éƒ¨åˆ†åQŒå› ä¸ºæ¯‹Æ¡åžƒåœ‘Ö›žæ”‰™ƒ½æœ‰ä¸€äº›å›žæ”¶ä¸æŽ‰çš„内存åQŒæ‰€ä»¥å¢žåŠ äº†(ji¨£n)å¤åˆ¶é‡ï¼Œå¯ÆD‡´æ—‰™—´å»‰™•¿ã€‚æ‰€ä»¥ï¼Œåžƒåœ¾å›žæ”¶çš„æ—¶é—´ä¹Ÿå¯ä»¥ä½œäØ“(f¨´)判断内存泄漏的依æ?/span>

         QåQ?span style="color: #0000ff">ä¸ÞZ»€ä¹ˆF(tu¨¢n)ull GC的次数越来越多?

         AåQ?span style="color: #ff6600">因此内存的积累,逐渐耗尽äº?ji¨£n)å¹´è€ä»£çš„å†…å­˜ï¼Œå¯ÆD‡´æ–°å¯¹è±¡åˆ†é…æ²¡æœ‰æ›´å¤šçš„½Iºé—´åQŒä»Žè€Œå¯¼è‡´é¢‘¾Jçš„垃圾回收

         Q:ä¸ÞZ»€ä¹ˆå¹´è€ä»£å ç”¨çš„内存越来越大?

         A:因䨓(f¨´)òq´è½»ä»£çš„内存无法被回æ”Óž¼Œ­‘Šæ¥­‘Šå¤šåœ°è¢«Copy到年老代

      三、性能调优

       é™¤äº†(ji¨£n)上述内存泄漏外,我们˜q˜å‘现CPU长期不èƒö3%åQŒç³»¾lŸåžåé‡ä¸å¤ŸåQŒé’ˆå¯?core×16Gã€?4bitçš„Linux服务器来è¯ß_(d¨¢)¼Œæ˜¯ä¸¥é‡çš„资源‹¹ªè´¹ã€?/p>

       åœ¨CPU负蝲不èƒö的同æ—Óž¼Œå¶å°”ä¼?x¨¬)有用户反映è¯äh±‚的时间过长,我们意识到必™åÕd¯¹½E‹åºå?qi¨¢ng)JVM˜q›è¡Œè°ƒä¼˜ã€‚从以下几个斚w¢˜q›è¡ŒåQ?/p>

      • ¾U¿ç¨‹æ± ï¼š(x¨¬)解决用户响应旉™—´é•¿çš„问题
      • ˜qžæŽ¥æ±?/li>
      • JVM启动参数åQšè°ƒæ•´å„代的内存比例和垃圑֛žæ”¶ç®—法,提高吞吐é‡?/li>
      • ½E‹åº½Ž—法åQ𿔹˜q›ç¨‹åºé€»è¾‘½Ž—法提高性能

        1.Java¾U¿ç¨‹æ± ï¼ˆjava.util.concurrent.ThreadPoolExecutoråQ?/p>

          大多数JVM6上的应用采用的线½E‹æ± éƒ½æ˜¯JDK自带的线½E‹æ± åQŒä¹‹æ‰€ä»¥æŠŠæˆç†Ÿçš„Java¾U¿ç¨‹æ± è¿›è¡Œç½—å—¦è¯´æ˜Žï¼Œæ˜¯å› ä¸ø™¯¥¾U¿ç¨‹æ± çš„è¡ŒäØ“(f¨´)与我们想象的有点出入。Java¾U¿ç¨‹æ± æœ‰å‡ ä¸ªé‡è¦çš„配¾|®å‚敎ͼš(x¨¬)

      • corePoolSizeåQšæ ¸å¿?j¨©)线½E‹æ•°åQˆæœ€æ–°çº¿½E‹æ•°åQ?/li>
      • maximumPoolSizeåQšæœ€å¤§çº¿½E‹æ•°åQŒè¶…˜q‡è¿™ä¸ªæ•°é‡çš„ä»ÕdŠ¡ä¼?x¨¬)被拒绝åQŒç”¨æˆ·å¯ä»¥é€šè¿‡RejectedExecutionHandler接口自定义处理方å¼?/li>
      • keepAliveTimeåQšçº¿½E‹ä¿æŒæ´»åŠ¨çš„æ—‰™—´
      • workQueueåQšå·¥ä½œé˜Ÿåˆ—,存放执行的ä“QåŠ?/li>

          Java¾U¿ç¨‹æ± éœ€è¦ä¼ å…¥ä¸€ä¸ªQueue参数åQˆworkQueueåQ‰ç”¨æ¥å­˜æ”¾æ‰§è¡Œçš„ä»ÕdŠ¡åQŒè€Œå¯¹Queue的不同选择åQŒçº¿½E‹æ± æœ‰å®Œå…¨ä¸åŒçš„è¡ŒäØ“(f¨´)åQ?/p>

          其实我们的要求很½Ž€å•,希望¾U¿ç¨‹æ± èƒ½è·Ÿè¿žæŽ¥æ± ä¸€æ øP¼Œèƒ½è®¾¾|®æœ€ž®çº¿½E‹æ•°ã€æœ€å¤§çº¿½E‹æ•°åQŒå½“最ž®æ•°<ä»ÕdŠ¡<最大数æ—Óž¼Œåº”该分配新的¾U¿ç¨‹å¤„理åQ›å½“ä»ÕdŠ¡>最大数æ—Óž¼Œåº”该½{‰å¾…有空闲线½E‹å†å¤„理该ä“Q务ã€?/p>

          但线½E‹æ± çš„设计思èµ\是,ä»ÕdŠ¡åº”è¯¥æ”‘Öˆ°Queue中,当Queue放不下时再考虑用新¾U¿ç¨‹å¤„理åQŒå¦‚æžœQ(j¨¬ng)ueue满且无法‹z„¡”Ÿæ–°çº¿½E‹ï¼Œž®±æ‹’¾lè¯¥ä»ÕdŠ¡ã€‚è®¾è®¡å¯¼è‡?#8220;先放½{‰æ‰§è¡?#8221;ã€?#8220;放不下再执行”ã€?#8220;拒绝不等å¾?#8221;。所以,æ ÒŽ(gu¨©)®ä¸åŒçš„Queue参数åQŒè¦æé«˜åžåé‡ä¸èƒ½ä¸€å‘›_œ°å¢žå¤§maximumPoolSizeã€?/p>

          当然åQŒè¦è¾‘Öˆ°æˆ‘们的目标,必须对线½E‹æ± ˜q›è¡Œä¸€å®šçš„ž®è£…åQŒå¹¸˜qçš„æ˜¯ThreadPoolExecutor中留äº?ji¨£n)èƒö够的自定义接口以帮助我们辑ֈ°ç›®æ ‡ã€‚我们封装的方式是:(x¨¬)

      • 以SynchronousQueueä½œäØ“(f¨´)参数åQŒä‹ÉmaximumPoolSize发挥作用åQŒä»¥é˜²æ­¢¾U¿ç¨‹è¢«æ— é™åˆ¶çš„分配,同时可以通过提高maximumPoolSize来提高系¾lŸåžåé‡
      • 自定义一个RejectedExecutionHandleråQŒå½“¾U¿ç¨‹æ•°è¶…˜q‡maximumPoolSize时进行处理,处理方式为隔一ŒD‰|—¶é—´æ£€æŸ¥çº¿½E‹æ± æ˜¯å¦å¯ä»¥æ‰§è¡Œæ–°TaskåQŒå¦‚果可以把拒绝的Task重新攑օ¥åˆ°çº¿½E‹æ± åQŒæ£€æŸ¥çš„æ—‰™—´ä¾èµ–keepAliveTime的大ž®ã€?/li>

        2.˜qžæŽ¥æ± ï¼ˆorg.apache.commons.dbcp.BasicDataSourceåQ?/p>

          在ä‹É用org.apache.commons.dbcp.BasicDataSourceçš„æ—¶å€™ï¼Œå› äØ“(f¨´)之前采用äº?ji¨£n)默认配¾|®ï¼Œæ‰€ä»¥å½“讉K—®é‡å¤§æ—Óž¼Œé€šè¿‡JMX观察到很多Tomcat¾U¿ç¨‹éƒ½é˜»å¡žåœ¨BasicDataSource使用的Apache ObjectPool的锁上,直接原因当时是因为BasicDataSource˜qžæŽ¥æ± çš„æœ€å¤§è¿žæŽ¥æ•°è®„¡½®çš„太ž®ï¼Œé»˜è®¤çš„BasicDataSource配置åQŒä»…使用8个最大连接ã€?/p>

          我还观察åˆîC¸€ä¸ªé—®é¢˜ï¼Œå½“较长的旉™—´ä¸è®¿é—®ç³»¾lŸï¼Œæ¯”如2天,DB上的Mysqlä¼?x¨¬)断掉所以的˜qžæŽ¥åQŒå¯¼è‡´è¿žæŽ¥æ± ä¸­ç¼“存的˜qžæŽ¥ä¸èƒ½ç”¨ã€‚䨓(f¨´)äº?ji¨£n)解册™¿™äº›é—®é¢˜ï¼Œæˆ‘们充分研究了(ji¨£n)BasicDataSourceåQŒå‘çŽîCº†(ji¨£n)一些优化的点:(x¨¬)

      • Mysql默认支持100个链接,所以每个连接池的配¾|®è¦æ ÒŽ(gu¨©)®é›†ç¾¤ä¸­çš„æœºå™¨æ•°è¿›è¡Œï¼Œå¦‚有2台服务器åQŒå¯æ¯ä¸ªè®„¡½®ä¸?0
      • initialSizeåQšå‚数是一直打开的连接数
      • minEvictableIdleTimeMillisåQšè¯¥å‚数讄¡½®æ¯ä¸ª˜qžæŽ¥çš„空闲时é—ß_(d¨¢)¼Œ­‘…过˜q™ä¸ªæ—‰™—´˜qžæŽ¥ž®†è¢«å…³é—­
      • timeBetweenEvictionRunsMillisåQšåŽå°çº¿½E‹çš„˜qè¡Œå‘¨æœŸåQŒç”¨æ¥æ£€‹¹‹è¿‡æœŸè¿žæŽ?/li>
      • maxActiveåQšæœ€å¤§èƒ½åˆ†é…çš„è¿žæŽ¥æ•°
      • maxIdleåQšæœ€å¤§ç©ºé—²æ•°åQŒå½“˜qžæŽ¥ä½¿ç”¨å®Œæ¯•后发现连接数大于maxIdleåQŒè¿žæŽ¥å°†è¢«ç›´æŽ¥å…³é—­ã€‚只有initialSize < x < maxIdle的连接将被定期检‹¹‹æ˜¯å¦è¶…期。这个参æ•îC¸»è¦ç”¨æ¥åœ¨å³°å€ÆD®¿é—®æ—¶æé«˜åžåé‡ã€?/li>
      • initialSize是如何保持的åQŸç»˜q‡ç ”½I¶ä»£ç å‘玎ͼŒBasicDataSourceä¼?x¨¬)关闭所有超期的˜qžæŽ¥åQŒç„¶åŽå†æ‰“å¼€initialSize数量的连接,˜q™ä¸ªç‰ÒŽ(gu¨©)€§ä¸ŽminEvictableIdleTimeMillis、timeBetweenEvictionRunsMillis一起保证了(ji¨£n)所有超期的initialSize˜qžæŽ¥éƒ½ä¼š(x¨¬)被重新连接,从而避免了(ji¨£n)Mysql长时间无动作ä¼?x¨¬)断掉连接的问题ã€?/li>

        3.JVM参数

          在JVM启动参数中,可以讄¡½®è·Ÿå†…存、垃圑֛žæ”¶ç›¸å…³çš„一些参数设¾|®ï¼Œé»˜è®¤æƒ…况不做ä»ÖM½•讄¡½®JVMä¼?x¨¬)工作的很好åQŒä½†å¯¹ä¸€äº›é…¾|®å¾ˆå¥½çš„Server和具体的应用必须仔细调优才能获得最ä½Ïx€§èƒ½ã€‚通过讄¡½®æˆ‘们希望辑ֈ°ä¸€äº›ç›®æ ‡ï¼š(x¨¬)

      • GC的时间èƒö够的ž®?/li>
      • GC的次数èƒö够的ž®?/li>
      • 发生Full GC的周期èƒö够的é•?/li>

        前两个目前是相æ?zh¨¨n)–的,要想GCæ—‰™—´ž®å¿…™å»è¦ä¸€ä¸ªæ›´ž®çš„堆,要保证GC‹Æ¡æ•°­‘›_¤Ÿž®‘,必须保证一个更大的堆,我们只能取其òqŒ™¡¡ã€?/p>

         åQ?åQ‰é’ˆå¯¹JVM堆的讄¡½®ä¸€èˆ¬ï¼Œå¯ä»¥é€šè¿‡-Xms -Xmx限定其最ž®ã€æœ€å¤§å€û|¼Œä¸ÞZº†(ji¨£n)防止垃圾攉™›†å™¨åœ¨æœ€ž®ã€æœ€å¤§ä¹‹é—´æ”¶¾~©å †è€Œäñ”生额外的旉™—´åQŒæˆ‘们通常把最大、最ž®è®¾¾|®äØ“(f¨´)相同的å€?br />   åQ?åQ‰å¹´è½ÖM»£å’Œå¹´è€ä»£ž®†æ ¹æ®é»˜è®¤çš„æ¯”例åQ?åQ?åQ‰åˆ†é…å †å†…å­˜åQŒå¯ä»¥é€šè¿‡è°ƒæ•´äºŒè€…之间的比率NewRadio来调整二者之间的大小åQŒä¹Ÿå¯ä»¥é’ˆå¯¹å›žæ”¶ä»£ï¼Œæ¯”如òq´è½»ä»£ï¼Œé€šè¿‡ -XX:newSize -XX:MaxNewSize来设¾|®å…¶¾lå¯¹å¤§å°ã€‚åŒæ øP¼Œä¸ÞZº†(ji¨£n)防止òq´è½»ä»£çš„堆收¾~©ï¼Œæˆ‘们通常ä¼?x¨¬)æŠ?XX:newSize -XX:MaxNewSize讄¡½®ä¸ºåŒæ ·å¤§ž®?/p>

         åQ?åQ‰å¹´è½ÖM»£å’Œå¹´è€ä»£è®„¡½®å¤šå¤§æ‰ç®—合理åQŸè¿™ä¸ªæˆ‘问题毫无疑问是没有答案的åQŒå¦åˆ™ä¹Ÿž®×ƒ¸ä¼?x¨¬)有调优。我们观察一下二者大ž®å˜åŒ–有哪些影响

      • 更大的年è½ÖM»£å¿…ç„¶å¯ÆD‡´æ›´å°çš„年老代åQŒå¤§çš„å¹´è½ÖM»£ä¼?x¨¬)åšg长普通GC的周期,但会(x¨¬)增加每次GC的时é—ß_(d¨¢)¼›ž®çš„òq´è€ä»£ä¼?x¨¬)导致更频繁的Full GC
      • 更小的年è½ÖM»£å¿…ç„¶å¯ÆD‡´æ›´å¤§òq´è€ä»£åQŒå°çš„å¹´è½ÖM»£ä¼?x¨¬)导致普通GC很频¾Jï¼Œä½†æ¯‹Æ¡çš„GCæ—‰™—´ä¼?x¨¬)更短;大的òq´è€ä»£ä¼?x¨¬)减ž®‘Full GC的频çŽ?/li>
      • 如何选择应该依赖应用½E‹åºå¯¹è±¡ç”Ÿå‘½å‘¨æœŸçš„分布情况:(x¨¬)如果应用存在大量的äÍ(f¨´)时对象,应该选择更大的年è½ÖM»£åQ›å¦‚果存在相对较多的持久对象åQŒå¹´è€ä»£åº”该适当增大。但很多应用都没有这æ äh˜Žæ˜„¡š„ç‰ÒŽ(gu¨©)€§ï¼Œåœ¨æŠ‰æ‹©æ—¶åº”该æ ÒŽ(gu¨©)®ä»¥ä¸‹ä¸¤ç‚¹åQšï¼ˆAåQ‰æœ¬ç€Full GCž®½é‡ž®‘的原则åQŒè®©òq´è€ä»£ž®½é‡¾~“存常用对象åQŒJVM的默认比ä¾?åQ?也是˜q™ä¸ªé“理 åQˆBåQ‰é€šè¿‡è§‚察应用一ŒD‰|—¶é—ß_(d¨¢)¼Œçœ‹å…¶ä»–在峰值时òq´è€ä»£ä¼?x¨¬)占多少内存åQŒåœ¨ä¸åª„(ji¨£ng)响Full GC的前提下åQŒæ ¹æ®å®žé™…情况加大年è½ÖM»£åQŒæ¯”如可以把比例控制åœ?åQ?。但应该¾l™å¹´è€ä»£è‡›_°‘预留1/3的增长空é—?/li>

        åQ?åQ‰åœ¨é…ç½®è¾ƒå¥½çš„æœºå™¨ä¸ŠåQˆæ¯”如多核、大内存åQ‰ï¼Œå¯ä»¥ä¸ºå¹´è€ä»£é€‰æ‹©òq¶è¡Œæ”‰™›†½Ž—法åQ?-XX:+UseParallelOldGC åQŒé»˜è®¤äØ“(f¨´)Serial攉™›†

        åQ?åQ‰çº¿½E‹å †æ ˆçš„讄¡½®åQšæ¯ä¸ªçº¿½E‹é»˜è®¤ä¼š(x¨¬)å¼€å?M的堆栈,用于存放栈å“á、调用参数、局部变量等åQŒå¯¹å¤§å¤šæ•°åº”用而言˜q™ä¸ªé»˜è®¤å€¼å¤ªäº?ji¨£n),一èˆ?56Kž®Þpƒö用。理è®ÞZ¸ŠåQŒåœ¨å†…存不变的情况下åQŒå‡ž®‘每个线½E‹çš„堆栈åQŒå¯ä»¥äñ”生更多的¾U¿ç¨‹åQŒä½†˜q™å®žé™…上˜q˜å—限于操作¾pȝ»Ÿã€?/p>

        åQ?åQ‰å¯ä»¥é€šè¿‡ä¸‹é¢çš„参数打Heap Dump信息

      • -XX:HeapDumpPath
      • -XX:+PrintGCDetails
      • -XX:+PrintGCTimeStamps
      • -Xloggc:/usr/aaa/dump/heap_trace.txt

          通过下面参数可以控制OutOfMemoryError时打印堆的信æ?/p>

      • -XX:+HeapDumpOnOutOfMemoryError

       è¯ïL(f¨¥ng)œ‹ä¸€ä¸‹ä¸€ä¸ªæ—¶é—´çš„Java参数配置åQšï¼ˆæœåŠ¡å™¨ï¼š(x¨¬)Linux 64BitåQ?Core×16GåQ?/p>

       JAVA_OPTS="$JAVA_OPTS -server -Xms3G -Xmx3G -Xss256k -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/aaa/dump -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/usr/aaa/dump/heap_trace.txt -XX:NewSize=1G -XX:MaxNewSize=1G"

      ¾lè¿‡è§‚察该配¾|®éžå¸¸ç¨³å®šï¼Œæ¯æ¬¡æ™®é€šGC的时间在10ms左右åQŒFull GC基本不发生,或隔很长很长的时间才发生一‹Æ?/p>

      通过分析dumpæ–‡äšg可以发现åQŒæ¯ä¸?ž®æ—¶éƒ½ä¼š(x¨¬)发生一‹Æ¡Full GCåQŒç»˜q‡å¤šæ–ÒŽ(gu¨©)±‚证,只要在JVM中开启了(ji¨£n)JMX服务åQŒJMXž®†ä¼š(x¨¬)1ž®æ—¶æ‰§è¡Œä¸€‹Æ¡Full GC以清除引用,关于˜q™ç‚¹è¯·å‚考附件文档ã€?/span>

       4.½E‹åº½Ž—法调优åQšæœ¬‹Æ¡ä¸ä½œäØ“(f¨´)重点

      参考资料:(x¨¬)

      http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html



      ]]>
      Java GC 垃圾攉™›† http://www.aygfsteel.com/stevenjohn/archive/2013/05/28/399870.htmlabinabinTue, 28 May 2013 06:31:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2013/05/28/399870.htmlhttp://www.aygfsteel.com/stevenjohn/comments/399870.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2013/05/28/399870.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/399870.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/399870.htmlJava堆,分配对象实例所在空é—ß_(d¨¢)¼Œæ˜¯GC的主要对象。分ä¸?/div>
       æ–°ç”Ÿä»?Young Generation/New)
       è€å¹´ä»?Tenured Generation/Old)
      新生代又划分�/div>
       Eden Space
       From Survivor/Survivor 0
       To Survivor/Survivor 1
      新生代要如此划分是因为新生代使用的GC½Ž—法是复制收集算法。这¿Uç®—法效率较高,而GC主要是发生在对象¾lå¸¸æ¶ˆäº¡çš„æ–°ç”Ÿä»£åQŒå› æ­¤æ–°ç”Ÿä»£é€‚合使用˜q™ç§å¤åˆ¶æ”‰™›†½Ž—法。由于有一个假设:(x¨¬)在一‹Æ¡æ–°ç”Ÿä»£çš„GC(Minor GC)后大部分的对象占用的内存都会(x¨¬)被回æ”Óž¼Œå› æ­¤ç•™å­˜çš„æ”¾¾|®GC后仍然活的对象的½Iºé—´ž®±æ¯”较小äº?ji¨£n)。这个留存的½Iºé—´ž®±æ˜¯Survivor spaceåQšFrom Survivor或To Survivor。这两个Survivor½Iºé—´æ˜¯ä¸€æ ·å¤§ž®çš„。例如,新生代大ž®æ˜¯10M(Xmn10M)åQŒé‚£ä¹ˆç¼ºçœæƒ…况下(-XX:SurvivorRatio=8)åQŒEden Space æ˜?MåQŒFromå’ŒTo都是1Mã€?/div>
      在new一个对象时åQŒå…ˆåœ¨Eden Space上分配,如果Eden Space½Iºé—´ä¸å¤Ÿž®Þp¦åšä¸€‹Æ¡Minor GC。Minor GC后,要把Edenå’ŒFrom中仍然活着的对象们复制到To½Iºé—´ä¸­åŽ»ã€‚å¦‚æžœTo½Iºé—´ä¸èƒ½å®¹çº³Minor GC后活着的某个对象,那么该对象就被promote到老年代空间。从Eden½Iºé—´è¢«å¤åˆ¶åˆ°To½Iºé—´çš„对象就有了(ji¨£n)age=1。此age=1的对象如果在下一‹Æ¡çš„Minor GC后仍然存?g¨°u)z»ï¼Œå®ƒè¿˜ä¼?x¨¬)被复制到另一个Survivor½Iºé—´(å¦‚æžœè®¤äØ“(f¨´)Fromå’ŒTo是固定的åQŒå°±æ˜¯åˆä»ŽTo回到äº?ji¨£n)From½Iºé—´)åQŒè€Œå®ƒçš„age=2。如此反复,如果age大于某个阈å€?-XX:MaxTenuringThreshold=n)åQŒé‚£ä¸ªè¯¥å¯¹è±¡ž®×ƒ¹Ÿå¯ä»¥promote到老年代了(ji¨£n)ã€?/div>
      如果Survivor½Iºé—´ä¸­ç›¸åŒage(例如åQŒage=5)对象的æ€Õd’Œå¤§äºŽ½{‰äºŽSurvivor½Iºé—´çš„一半,那么age>=5的对象在下一‹Æ¡Minor GC后就可以直接promote到老年代,而不用等到age增长到阈倹{€?/div>
      在做Minor GCæ—Óž¼Œåªå¯¹æ–°ç”Ÿä»£åšå›žæ”¶åQŒä¸ä¼?x¨¬)回收老年代。即使老年代的对象无äh索引也将仍然存活åQŒç›´åˆîC¸‹ä¸€‹Æ¡Full GCã€?/div>

      ]]>JVM参数配置大全http://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391310.htmlabinabinWed, 14 Nov 2012 05:48:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391310.htmlhttp://www.aygfsteel.com/stevenjohn/comments/391310.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391310.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/391310.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/391310.html

      前阵子遇到几个面试题都是关于对Java内存控制çš?因此从网上找到这½‹‡æ–‡ç«?希望自己对Java的内存分配有重新的认è¯?

      /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

      1. 堆大ž®è®¾¾|?br />JVM 中最大堆大小有三斚w¢é™åˆ¶åQšç›¸å…Ïx“ä½œç³»¾lŸçš„æ•°æ®æ¨¡åž‹åQ?2-bt˜q˜æ˜¯64-bitåQ‰é™åˆÓž¼›¾pȝ»Ÿçš„可用虚拟内存限åˆÓž¼›¾pȝ»Ÿçš„可用物理内存限制ã€?2位系¾lŸä¸‹åQŒä¸€èˆ¬é™åˆ¶åœ¨1.5G~2GåQ?4为操作系¾lŸå¯¹å†…存无限制。我在Windows Server 2003 ¾pȝ»ŸåQ?.5G物理内存åQŒJDK5.0下测试,最大可讄¡½®ä¸?478mã€?br />典型讄¡½®åQ?/strong>
        • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
          -Xmx3550måQšè®¾¾|®JVMæœ€å¤§å¯ç”¨å†…å­˜äØ“(f¨´)3550Mã€?br />-Xms3550måQšè®¾¾|®JVMä¿?j¨©)ä‹É内存ä?550m。此值可以设¾|®ä¸Ž-Xmx相同åQŒä»¥é¿å…æ¯æ¬¡åžƒåœ¾å›žæ”¶å®ŒæˆåŽJVM重新分配内存ã€?br />-Xmn2gåQšè®¾¾|®å¹´è½ÖM»£å¤§å°ä¸?Gã€?strong>整个堆大ž®?òq´è½»ä»£å¤§ž®?+ òq´è€ä»£å¤§å° + 持久代大ž®?/strong>。持久代一般固定大ž®äØ“(f¨´)64måQŒæ‰€ä»¥å¢žå¤§å¹´è½ÖM»£åŽï¼Œž®†ä¼š(x¨¬)减小òq´è€ä»£å¤§å°ã€‚此值对¾pȝ»Ÿæ€§èƒ½å½±å“è¾ƒå¤§åQŒSun官方推荐配置为整个堆çš?/8ã€?br />-Xss128kåQšè®¾¾|®æ¯ä¸ªçº¿½E‹çš„堆栈大小。JDK5.0以后每个¾U¿ç¨‹å †æ ˆå¤§å°ä¸?MåQŒä»¥å‰æ¯ä¸ªçº¿½E‹å †æ ˆå¤§ž®äØ“(f¨´)256K。更具应用的¾U¿ç¨‹æ‰€éœ€å†…存大小˜q›è¡Œè°ƒæ•´ã€‚在相同物理内存下,减小˜q™ä¸ªå€ÆDƒ½ç”Ÿæˆæ›´å¤šçš„线½E‹ã€‚但是操作系¾lŸå¯¹ä¸€ä¸ªè¿›½E‹å†…的线½E‹æ•°˜q˜æ˜¯æœ‰é™åˆ¶çš„åQŒä¸èƒ½æ— é™ç”Ÿæˆï¼Œ¾léªŒå€¼åœ¨3000~5000左右ã€?
        • java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
          -XX:NewRatio=4:讄¡½®òq´è½»ä»£ï¼ˆåŒ…括Eden和两个Survivor区)(j¨ª)与年老代的比å€û|¼ˆé™¤åŽ»æŒä¹…ä»£ï¼‰(j¨ª)。设¾|®äØ“(f¨´)4åQŒåˆ™òq´è½»ä»£ä¸Žòq´è€ä»£æ‰€å æ¯”å€égØ“(f¨´)1åQ?åQŒå¹´è½ÖM»£å æ•´ä¸ªå †æ ˆçš„1/5
          -XX:SurvivorRatio=4åQšè®¾¾|®å¹´è½ÖM»£ä¸­EdenåŒÞZ¸ŽSurvivor区的大小比倹{€‚设¾|®äØ“(f¨´)4åQŒåˆ™ä¸¤ä¸ªSurvivoråŒÞZ¸Žä¸€ä¸ªEden区的比å€égØ“(f¨´)2:4åQŒä¸€ä¸ªSurvivor区占整个òq´è½»ä»£çš„1/6
          -XX:MaxPermSize=16m:讄¡½®æŒä¹…代大ž®äØ“(f¨´)16mã€?br />-XX:MaxTenuringThreshold=0åQšè®¾¾|®åžƒåœ¾æœ€å¤§å¹´é¾„ã€?strong>如果讄¡½®ä¸?的话åQŒåˆ™òq´è½»ä»£å¯¹è±¡ä¸¾lè¿‡Survivor区,直接˜q›å…¥òq´è€ä»£
          。对于年老代比较多的应用åQŒå¯ä»¥æé«˜æ•ˆçއã€?strong>如果ž®†æ­¤å€ÆD®¾¾|®äØ“(f¨´)一个较大å€û|¼Œåˆ™å¹´è½ÖM»£å¯¹è±¡ä¼?x¨¬)在SurvivoråŒø™¿›è¡Œå¤š‹Æ¡å¤åˆÓž¼Œ˜q™æ ·å¯ä»¥å¢žåŠ å¯¹è±¡å†å¹´è½ÖM»£çš„å­˜?g¨°u)zÀL—¶é—?/strong>åQŒå¢žåŠ åœ¨òq´è½»ä»£å³è¢«å›žæ”¶çš„æ¦‚论ã€?/li>
      2. 回收器选择
        JVM¾l™äº†(ji¨£n)三种选择åQ?strong>串行攉™›†å™¨ã€åÆˆè¡Œæ”¶é›†å™¨ã€åÆˆå‘æ”¶é›†å™¨
        åQŒä½†æ˜¯ä¸²è¡Œæ”¶é›†å™¨åªé€‚用于小数据量的情况åQŒæ‰€ä»¥è¿™é‡Œçš„选择主要针对òq¶è¡Œæ”‰™›†å™¨å’Œòq¶å‘攉™›†å™¨ã€‚默认情况下åQŒJDK5.0以前都是使用串行攉™›†å™¨ï¼Œå¦‚果想ä‹É用其他收集器需要在启动时加入相应参数。JDK5.0以后åQŒJVMä¼?x¨¬)根据当å?a >¾pȝ»Ÿé…ç½®˜q›è¡Œåˆ¤æ–­ã€?
        1. 吞吐量优å…?/strong>çš„åÆˆè¡Œæ”¶é›†å™¨
          如上文所˜qŽÍ¼Œòq¶è¡Œæ”‰™›†å™¨ä¸»è¦ä»¥åˆ°è¾¾ä¸€å®šçš„åžåé‡äØ“(f¨´)目标åQŒé€‚用于科学技术和后台处理½{‰ã€?br />典型配置åQ?
          • java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
            -XX:+UseParallelGCåQšé€‰æ‹©åžƒåœ¾æ”‰™›†å™¨äØ“(f¨´)òq¶è¡Œæ”‰™›†å™¨ã€?strong>此配¾|®ä»…对年è½ÖM»£æœ‰æ•ˆã€‚即上述配置下,òq´è½»ä»£ä‹Éç”¨åÆˆå‘æ”¶é›†ï¼Œè€Œå¹´è€ä»£ä»æ—§ä½¿ç”¨ä¸²è¡Œæ”‰™›†ã€?br />
            -XX:ParallelGCThreads=20åQšé…¾|®åƈ行收集器的线½E‹æ•°åQŒå³åQšåŒæ—¶å¤šž®‘个¾U¿ç¨‹ä¸€èµ¯‚¿›è¡Œåžƒåœ‘Ö›žæ”¶ã€‚此值最好配¾|®ä¸Žå¤„理器数目相½{‰ã€?
          • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
            -XX:+UseParallelOldGCåQšé…¾|®å¹´è€ä»£åžƒåœ¾æ”‰™›†æ–¹å¼ä¸ºåƈ行收集。JDK6.0支持对年老代òq¶è¡Œæ”‰™›†ã€?
          • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
            -XX:MaxGCPauseMillis=100:讄¡½®æ¯æ¬¡òq´è½»ä»£åžƒåœ‘Ö›žæ”¶çš„æœ€é•¿æ—¶é—ß_(d¨¢)¼Œå¦‚果无法满èƒö此时é—ß_(d¨¢)¼ŒJVMä¼?x¨¬)自动调整年è½ÖM»£å¤§å°åQŒä»¥æ»¡èƒö此倹{€?
          • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100-XX:+UseAdaptiveSizePolicy
            -XX:+UseAdaptiveSizePolicy
            åQšè®¾¾|®æ­¤é€‰é¡¹åŽï¼Œòq¶è¡Œæ”‰™›†å™¨ä¼š(x¨¬)自动选择òq´è½»ä»£åŒºå¤§å°å’Œç›¸åº”çš„Survivor区比例,以达到目标系¾lŸè§„定的最低相应时间或者收集频率等åQŒæ­¤å€¼å¾è®®ä‹Éç”¨åÆˆè¡Œæ”¶é›†å™¨æ—Óž¼Œä¸€ç›´æ‰“å¼€ã€?/li>
      3. 响应旉™—´ä¼˜å…ˆçš„åÆˆå‘æ”¶é›†å™¨
        如上文所˜qŽÍ¼Œòq¶å‘攉™›†å™¨ä¸»è¦æ˜¯ä¿è¯¾pȝ»Ÿçš„响应时é—ß_(d¨¢)¼Œå‡å°‘垃圾攉™›†æ—¶çš„停顿旉™—´ã€‚适用于应用服务器、电(sh¨´)信领域等ã€?br />典型配置åQ?
        • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
          -XX:+UseConcMarkSweepGCåQšè®¾¾|®å¹´è€ä»£ä¸ºåƈ发收集。测试中配置˜q™ä¸ªä»¥åŽåQ?XX:NewRatio=4的配¾|®å¤±æ•ˆäº†(ji¨£n)åQŒåŽŸå› ä¸æ˜Žã€‚æ‰€ä»¥ï¼Œæ­¤æ—¶òq´è½»ä»£å¤§ž®æœ€å¥½ç”¨-Xmn讄¡½®ã€?br />-XX:+UseParNewGC:讄¡½®òq´è½»ä»£äØ“(f¨´)òq¶è¡Œæ”‰™›†ã€‚可与CMS攉™›†åŒæ—¶ä½¿ç”¨ã€‚JDK5.0以上åQŒJVMä¼?x¨¬)根据系¾lŸé…¾|®è‡ªè¡Œè®¾¾|®ï¼Œæ‰€ä»¥æ— éœ€å†è®¾¾|®æ­¤å€¹{€?
        • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
          -XX:CMSFullGCsBeforeCompactionåQšç”±äºŽåƈ发收集器不对内存½Iºé—´˜q›è¡ŒåŽ‹ç¾ƒã€æ•´ç†ï¼Œæ‰€ä»¥è¿è¡Œä¸€ŒD‰|—¶é—´ä»¥åŽä¼š(x¨¬)产生“¼„Žç‰‡”åQŒä‹Éå¾—è¿è¡Œæ•ˆçŽ‡é™ä½Žã€‚æ­¤å€ÆD®¾¾|®è¿è¡Œå¤šž®‘次GC以后对内存空间进行压¾~©ã€æ•´ç†ã€?br />-XX:+UseCMSCompactAtFullCollectionåQšæ‰“å¼€å¯¹å¹´è€ä»£çš„åŽ‹¾~©ã€‚可能会(x¨¬)影响性能åQŒä½†æ˜¯å¯ä»¥æ¶ˆé™¤ç¢Žç‰?/li>
    1. 辅助信息
      JVM提供äº?ji¨£n)大量命令行参数åQŒæ‰“åîC¿¡æ¯ï¼Œä¾›è°ƒè¯•ä‹É用。主要有以下一些:(x¨¬)
      • -XX:+PrintGC
        输出形式åQš[GC 118250K->113543K(130112K), 0.0094143 secs]

                        [Full GC 121376K->10414K(130112K), 0.0650971 secs]

      • -XX:+PrintGCDetails
        输出形式åQš[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]

                        [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

      • -XX:+PrintGCTimeStamps -XX:+PrintGCåQšPrintGCTimeStamps可与上面两个混合使用
        输出形式åQ?strong>11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
      • -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,½E‹åºæœªä¸­æ–­çš„æ‰§è¡Œæ—‰™—´ã€‚å¯ä¸Žä¸Šé¢æØœåˆä‹Éç”?br />输出形式åQ?strong>Application time: 0.5291524 seconds
      • -XX:+PrintGCApplicationStoppedTimeåQšæ‰“å°åžƒåœ‘Ö›žæ”¶æœŸé—´ç¨‹åºæš‚停的旉™—´ã€‚å¯ä¸Žä¸Šé¢æØœåˆä‹Éç”?br />输出形式åQ?strong>Total time for which application threads were stopped: 0.0468229 seconds
      • -XX:PrintHeapAtGC:打印GC前后的详¾l†å †æ ˆä¿¡æ?br />输出形式åQ?br />34.702: [GC {Heap before gc invocations=7:
        def new generation   total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
        eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
        from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000)
        to   space 6144K,   0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
        tenured generation   total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
        the space 69632K,   3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
        compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
           the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
            ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
            rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
        34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
        def new generation   total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
        eden space 49152K,   0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
        from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
        to   space 6144K,   0% used [0x221d0000, 0x221d0000, 0x227d0000)
        tenured generation   total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
        the space 69632K,   4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
        compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
           the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
            ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
            rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
        }
        , 0.0757599 secs]
      • -Xloggc:filename:与上面几个配合ä‹É用,把相å…Ïx—¥å¿—信息记录到文äšg以便分析ã€?/li>
    2. 常见配置汇�/strong>
      1. 堆设¾|?
        • -Xms:初始堆大ž®?
        • -Xmx:最大堆大小
        • -XX:NewSize=n:讄¡½®òq´è½»ä»£å¤§ž®?
        • -XX:NewRatio=n:讄¡½®òq´è½»ä»£å’Œòq´è€ä»£çš„æ¯”倹{€‚如:ä¸?åQŒè¡¨½Cºå¹´è½ÖM»£ä¸Žå¹´è€ä»£æ¯”å€égØ“(f¨´)1åQ?åQŒå¹´è½ÖM»£å æ•´ä¸ªå¹´è½ÖM»£òq´è€ä»£å’Œçš„1/4
        • -XX:SurvivorRatio=n:òq´è½»ä»£ä¸­EdenåŒÞZ¸Žä¸¤ä¸ªSurvivor区的比倹{€‚注意Survivor区有两个。如åQ?åQŒè¡¨½CºEdenåQšSurvivor=3åQ?åQŒä¸€ä¸ªSurvivor区占整个òq´è½»ä»£çš„1/5
        • -XX:MaxPermSize=n:讄¡½®æŒä¹…代大ž®?/li>
    3. 攉™›†å™¨è®¾¾|?
      • -XX:+UseSerialGC:讄¡½®ä¸²è¡Œæ”‰™›†å™?
      • -XX:+UseParallelGC:讄¡½®òq¶è¡Œæ”‰™›†å™?
      • -XX:+UseParalledlOldGC:讄¡½®òq¶è¡Œòq´è€ä»£æ”‰™›†å™?
      • -XX:+UseConcMarkSweepGC:讄¡½®òq¶å‘攉™›†å™?/li>
    4. 垃圾回收¾lŸè®¡ä¿¡æ¯
      • -XX:+PrintGC
      • -XX:+PrintGCDetails
      • -XX:+PrintGCTimeStamps
      • -Xloggc:filename
    5. òq¶è¡Œæ”‰™›†å™¨è®¾¾|?
      • -XX:ParallelGCThreads=n:讄¡½®òq¶è¡Œæ”‰™›†å™¨æ”¶é›†æ—¶ä½¿ç”¨çš„CPUæ•°ã€‚åÆˆè¡Œæ”¶é›†çº¿½E‹æ•°ã€?
      • -XX:MaxGCPauseMillis=n:讄¡½®òq¶è¡Œæ”‰™›†æœ€å¤§æš‚停时é—?
      • -XX:GCTimeRatio=n:讄¡½®åžƒåœ¾å›žæ”¶æ—‰™—´å ç¨‹åºè¿è¡Œæ—¶é—´çš„癑ֈ†æ¯”ã€‚å…¬å¼äØ“(f¨´)1/(1+n)
    6. òq¶å‘攉™›†å™¨è®¾¾|?
      • -XX:+CMSIncrementalMode:讄¡½®ä¸ºå¢žé‡æ¨¡å¼ã€‚适用于单CPU情况ã€?
      • -XX:ParallelGCThreads=n:讄¡½®òq¶å‘攉™›†å™¨å¹´è½ÖM»£æ”‰™›†æ–¹å¼ä¸ºåƈ行收集时åQŒä‹É用的CPUæ•°ã€‚åÆˆè¡Œæ”¶é›†çº¿½E‹æ•°ã€?/li>
    7. 四、调优æ€È»“

      1. òq´è½»ä»£å¤§ž®é€‰æ‹©
        • 响应旉™—´ä¼˜å…ˆçš„应ç”?/strong>åQ?strong>ž®½å¯èƒ½è®¾å¤§ï¼Œç›´åˆ°æŽ¥è¿‘¾pȝ»Ÿçš„æœ€ä½Žå“åº”时间限åˆ?/strong>åQˆæ ¹æ®å®žé™…情况选择åQ‰ã€‚在此种情况下,òq´è½»ä»£æ”¶é›†å‘生的频率也是最ž®çš„。同æ—Óž¼Œå‡å°‘到达òq´è€ä»£çš„对象ã€?
        • 吞吐量优先的应用åQšå°½å¯èƒ½çš„设¾|®å¤§åQŒå¯èƒ½åˆ°è¾¾Gbit的程度。因为对响应旉™—´æ²¡æœ‰è¦æ±‚åQŒåžƒåœ¾æ”¶é›†å¯ä»¥åƈ行进行,一般适合8CPU以上的应用ã€?/li>
      2. òq´è€ä»£å¤§å°é€‰æ‹©
        • 响应旉™—´ä¼˜å…ˆçš„应ç”?/strong>åQšå¹´è€ä»£ä½¿ç”¨òq¶å‘攉™›†å™¨ï¼Œæ‰€ä»¥å…¶å¤§å°éœ€è¦å°å¿?j¨©)设¾|®ï¼Œä¸€èˆ¬è¦è€ƒè™‘òq¶å‘ä¼?x¨¬)话ç?/strong>å’?strong>ä¼?x¨¬)话持箋旉™—?/strong>½{‰ä¸€äº›å‚数。如果堆讄¡½®ž®äº†(ji¨£n)åQŒå¯ä»¥ä¼š(x¨¬)造成内存¼„Žç‰‡ã€é«˜å›žæ”¶é¢‘率以及(qi¨¢ng)应用暂停而ä‹É用传¾lŸçš„æ ‡è®°æ¸…除方式åQ›å¦‚果堆大了(ji¨£n)åQŒåˆ™éœ€è¦è¾ƒé•¿çš„æ”‰™›†æ—‰™—´ã€‚最优化的方案,一般需要参考以下数据获得:(x¨¬)
          • òq¶å‘垃圾攉™›†ä¿¡æ¯
          • æŒä¹…ä»£åÆˆå‘æ”¶é›†æ¬¡æ•?
          • 传统GC信息
          • 花在òq´è½»ä»£å’Œòq´è€ä»£å›žæ”¶ä¸Šçš„æ—‰™—´æ¯”例
      3. 减少òq´è½»ä»£å’Œòq´è€ä»£èŠÞp´¹çš„æ—¶é—ß_(d¨¢)¼Œä¸€èˆ¬ä¼š(x¨¬)提高应用的效çŽ?/li>
      4. 吞吐量优先的应用åQšä¸€èˆ¬åžåé‡ä¼˜å…ˆçš„应用都有一个很大的òq´è½»ä»£å’Œä¸€ä¸ªè¾ƒ?y¨­u)®çš„òq´è€ä»£ã€‚原因是åQŒè¿™æ ·å¯ä»¥å°½å¯èƒ½å›žæ”¶æŽ‰å¤§éƒ¨åˆ†çŸ­æœŸå¯¹è±¡åQŒå‡ž®‘中期的对象åQŒè€Œå¹´è€ä»£ž®½å­˜æ”ùN•¿æœŸå­˜?g¨°u)zÕd¯¹è±¡ã€?/li>
      5. 较小堆引èµïL(f¨¥ng)š„¼„Žç‰‡é—®é¢˜
        因䨓(f¨´)òq´è€ä»£çš„åÆˆå‘æ”¶é›†å™¨ä½¿ç”¨æ ‡è®°ã€æ¸…é™¤ç®—æ³•ï¼Œæ‰€ä»¥ä¸ä¼?x¨¬)对堆进行压¾~©ã€‚当攉™›†å™¨å›žæ”¶æ—¶åQŒä»–ä¼?x¨¬)把盔R‚»çš„空间进行合òqÓž¼Œ˜q™æ ·å¯ä»¥åˆ†é…¾l™è¾ƒå¤§çš„对象。但是,当堆½Iºé—´è¾ƒå°æ—Óž¼Œ˜qè¡Œä¸€ŒD‰|—¶é—´ä»¥åŽï¼Œž®×ƒ¼š(x¨¬)出现“¼„Žç‰‡”åQŒå¦‚æžœåÆˆå‘æ”¶é›†å™¨æ‰¾ä¸åˆ°èƒö够的½Iºé—´åQŒé‚£ä¹ˆåƈ发收集器ž®†ä¼š(x¨¬)停止åQŒç„¶åŽä‹É用传¾lŸçš„æ ‡è®°ã€æ¸…除方式进行回收。如果出çŽ?#8220;¼„Žç‰‡”åQŒå¯èƒ½éœ€è¦è¿›è¡Œå¦‚下配¾|®ï¼š(x¨¬)
        • -XX:+UseCMSCompactAtFullCollectionåQšä‹Éç”¨åÆˆå‘æ”¶é›†å™¨æ—Óž¼Œå¼€å¯å¯¹òq´è€ä»£çš„压¾~©ã€?
        • -XX:CMSFullGCsBeforeCompaction=0åQšä¸Šé¢é…¾|®å¼€å¯çš„æƒ…况下,˜q™é‡Œè®„¡½®å¤šå°‘‹Æ¡Full GC后,对年老代˜q›è¡ŒåŽ‹ç¾ƒ
      6. jvm的内存限�/li>

              windows2003æ˜?612M



      http://www.cnblogs.com/edwardlauxh/archive/2010/04/25/1918603.html

      ]]>JVM 环境参数配置http://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391309.htmlabinabinWed, 14 Nov 2012 05:40:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391309.htmlhttp://www.aygfsteel.com/stevenjohn/comments/391309.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391309.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/391309.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/391309.html典型JVM参数讄¡½®åQ? java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -Xmx3550måQšè®¾¾|®JVMæœ€å¤§å¯ç”¨å†…å­˜äØ“(f¨´)3550Mã€? -Xms3550måQšè®¾¾|®JVMä¿?j¨©)ä‹É内存ä?550m。此值可以设¾|®ä¸Ž-Xmx相同åQŒä»¥é¿å…æ¯æ¬¡åžƒåœ¾å›žæ”¶å®ŒæˆåŽJVM重新分配内存ã€? -Xmn2gåQšè®¾¾|®å¹´è½ÖM»£å¤§å°ä¸?G。整个堆大小=òq´è½»ä»£å¤§ž®?+ òq´è€ä»£å¤§å° + 持久代大ž®ã€‚持久代一般固定大ž®äØ“(f¨´)64måQŒæ‰€ä»¥å¢žå¤§å¹´è½ÖM»£åŽï¼Œž®†ä¼š(x¨¬)减小òq´è€ä»£å¤§å°ã€‚此值对¾pȝ»Ÿæ€§èƒ½å½±å“è¾ƒå¤§åQŒSun官方推荐配置为整个堆çš?/8ã€? -Xss128kåQšè®¾¾|®æ¯ä¸ªçº¿½E‹çš„堆栈大小。JDK5.0以后每个¾U¿ç¨‹å †æ ˆå¤§å°ä¸?MåQŒä»¥å‰æ¯ä¸ªçº¿½E‹å †æ ˆå¤§ž®äØ“(f¨´)256K。更具应用的¾U¿ç¨‹æ‰€éœ€å†…存大小˜q›è¡Œè°ƒæ•´ã€‚在相同物理内存下,减小˜q™ä¸ªå€ÆDƒ½ç”Ÿæˆæ›´å¤šçš„线½E‹ã€‚但是操作系¾lŸå¯¹ä¸€ä¸ªè¿›½E‹å†…的线½E‹æ•°˜q˜æ˜¯æœ‰é™åˆ¶çš„åQŒä¸èƒ½æ— é™ç”Ÿæˆï¼Œ¾léªŒå€¼åœ¨3000~5000左右ã€? java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0 -XX:NewRatio=4:讄¡½®òq´è½»ä»£ï¼ˆåŒ…括Eden和两个Survivor区)(j¨ª)与年老代的比å€û|¼ˆé™¤åŽ»æŒä¹…ä»£ï¼‰(j¨ª)。设¾|®äØ“(f¨´)4åQŒåˆ™òq´è½»ä»£ä¸Žòq´è€ä»£æ‰€å æ¯”å€égØ“(f¨´)1åQ?åQŒå¹´è½ÖM»£å æ•´ä¸ªå †æ ˆçš„1/5 -XX:SurvivorRatio=4åQšè®¾¾|®å¹´è½ÖM»£ä¸­EdenåŒÞZ¸ŽSurvivor区的大小比倹{€‚设¾|®äØ“(f¨´)4åQŒåˆ™ä¸¤ä¸ªSurvivoråŒÞZ¸Žä¸€ä¸ªEden区的比å€égØ“(f¨´)2:4åQŒä¸€ä¸ªSurvivor区占整个òq´è½»ä»£çš„1/6 -XX:MaxPermSize=16m:讄¡½®æŒä¹…代大ž®äØ“(f¨´)16mã€? -XX:MaxTenuringThreshold=0åQšè®¾¾|®åžƒåœ¾æœ€å¤§å¹´é¾„。如果设¾|®äØ“(f¨´)0的话åQŒåˆ™òq´è½»ä»£å¯¹è±¡ä¸¾lè¿‡Survivor区,直接˜q›å…¥òq´è€ä»£ã€‚对于年老代比较多的应用åQŒå¯ä»¥æé«˜æ•ˆçŽ‡ã€‚å¦‚æžœå°†æ­¤å€ÆD®¾¾|®äØ“(f¨´)一个较大å€û|¼Œåˆ™å¹´è½ÖM»£å¯¹è±¡ä¼?x¨¬)在SurvivoråŒø™¿›è¡Œå¤š‹Æ¡å¤åˆÓž¼Œ˜q™æ ·å¯ä»¥å¢žåŠ å¯¹è±¡å†å¹´è½ÖM»£çš„å­˜?g¨°u)zÀL—¶é—ß_(d¨¢)¼Œå¢žåŠ åœ¨å¹´è½ÖM»£åŒ™¢«å›žæ”¶çš„æ¦‚论ã€?/pre>

      ]]>
      利用 Runtime 监控 Java ¾pȝ»Ÿèµ„源http://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391305.htmlabinabinWed, 14 Nov 2012 05:01:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391305.htmlhttp://www.aygfsteel.com/stevenjohn/comments/391305.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2012/11/14/391305.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/391305.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/391305.html阅读全文

      ]]>
      Java内存溢出 http://www.aygfsteel.com/stevenjohn/archive/2012/10/25/390240.htmlabinabinThu, 25 Oct 2012 15:16:00 GMThttp://www.aygfsteel.com/stevenjohn/archive/2012/10/25/390240.htmlhttp://www.aygfsteel.com/stevenjohn/comments/390240.htmlhttp://www.aygfsteel.com/stevenjohn/archive/2012/10/25/390240.html#Feedback0http://www.aygfsteel.com/stevenjohn/comments/commentRss/390240.htmlhttp://www.aygfsteel.com/stevenjohn/services/trackbacks/390240.html

      内存溢出与数据库锁表的问题,可以说是开发äh员的噩梦åQŒä¸€èˆ¬çš„½E‹åºå¼‚常åQŒæ€ÀL˜¯å¯ä»¥çŸ¥é“在什么时候或是在什么操作步骤上出现äº?ji¨£n)异常,而且æ ÒŽ(gu¨©)®å †æ ˆä¿¡æ¯ä¹Ÿå¾ˆå®ÒŽ(gu¨©)˜“定位到程序中是某处出çŽîCº†(ji¨£n)问题。内存溢å‡ÞZ¸Žé”è¡¨åˆ™ä¸ç„?d¨°ng)ž¼Œä¸€èˆ¬çŽ°è±¡æ˜¯æ“ä½œä¸€èˆ¬æ—¶é—´åŽ¾pȝ»Ÿ­‘Šæ¥­‘Šæ…¢åQŒç›´åˆ°æ­»æœºï¼Œä½†åƈ不能明确是在什么操作上出现的,发生的时间点也没有规律,查看日志æˆ?span style="background-color: yellow; color: #ee6600" id="Mark">查看数据库也不能定位出问题的代码ã€?/p>

      更严重的是内存溢å‡ÞZ¸Žæ•°æ®åº“锁表在¾pȝ»Ÿå¼€å‘和单元‹¹‹è¯•阶段òq¶ä¸å®ÒŽ(gu¨©)˜“被发玎ͼŒå½“ç³»¾lŸæ­£å¼ä¸Š¾U¿ä¸€èˆ¬æ—¶é—´åŽåQŒæ“ä½œçš„òq¶å‘量上来了(ji¨£n)åQŒæ•°æ®ä¹Ÿ¿U¯ç¯äº?ji¨£n)一些,¾pȝ»Ÿž®±å®¹æ˜“出现内存溢出或是锁表的现象åQŒè€Œæ­¤æ—¶ç³»¾lŸåˆä¸èƒ½éšæ„åœæœºæˆ–重启,ä¸ÞZ¿®æ­£BUG带来很大的困难ã€?/p>

      æœ¬æ–‡ä»¥ç¬”è€…å¼€å‘å’Œæ”¯æŒçš„å¤šä¸ªé¡¹ç›®äØ“(f¨´)例,与大家分享在开发过½E‹ä¸­é‡åˆ°çš„Java内存溢出和数据库锁表的检‹¹‹å’Œå¤„理解决˜q‡ç¨‹ã€?/p>

      2åQŽå†…存溢出的分析
      内存溢出是指应用¾pȝ»Ÿä¸­å­˜åœ¨æ— æ³•回收的内存或ä‹É用的内存˜q‡å¤šåQŒæœ€¾lˆä‹Éå¾—ç¨‹åºè¿è¡Œè¦ç”¨åˆ°çš„å†…å­˜å¤§äºŽè™šæ‹Ÿæœºèƒ½æä¾›çš„æœ€å¤§å†…å­˜ã€‚äØ“(f¨´)äº?ji¨£n)解决Java中内存溢出问题,我们首先必须äº?ji¨£n)è§£Java是如何管理内存的。Java的内存管理就是对象的分配和释æ”ùN—®é¢˜ã€‚在Java中,内存的分配是ç”Þq¨‹åºå®Œæˆçš„åQŒè€Œå†…存的释放是由垃圾攉™›†å™?Garbage CollectionåQŒGC)完成的,½E‹åºå‘˜ä¸éœ€è¦é€šè¿‡è°ƒç”¨GC函数来释攑ֆ…å­˜ï¼Œå› äØ“(f¨´)不同的JVM实现者可能ä‹É用不同的½Ž—法½Ž¡ç†GCåQŒæœ‰çš„æ˜¯å†…存使用到达一定程度时åQŒGC才开始工作,也有定时执行的,有的是中断式执行GC。但GC只能回收无用òq¶ä¸”不再被其它对象引用的那些对象所占用的空间。Java的内存垃圑֛žæ”¶æœºåˆ¶æ˜¯ä»Žç¨‹åºçš„主要˜qè¡Œå¯¹è±¡å¼€å§‹æ£€æŸ¥å¼•用链åQŒå½“遍历一遍后发现没有被引用的孤立对象ž®×ƒ½œä¸ºåžƒåœ‘Ö›žæ”¶ã€?/p>

      引è“v内存溢出的原因有很多¿Uï¼Œå¸¸è§çš„æœ‰ä»¥ä¸‹å‡ ç§åQ?/p>

      l         内存中加载的数据量过于庞大,如一‹Æ¡ä»Žæ•°æ®åº“取å‡?gu¨®)™¿‡å¤šæ•°æ®ï¼?/p>

      l         集合¾cÖM¸­æœ‰å¯¹å¯¹è±¡çš„引用,使用完后未清½Iºï¼Œä½¿å¾—JVM不能回收åQ?/p>

      l         代码中存在死循环或åó@环äñ”生过多重复的对象实体åQ?/p>

      l         使用的第三方软äšg中的BUGåQ?/p>

      l         å¯åŠ¨å‚æ•°å†…å­˜å€ÆD®¾å®šçš„˜q‡å°åQ?/p>

      3åQŽå†…存溢出的解决
      内存溢出虽然很棘手,但也有相应的解决办法åQŒå¯ä»¥æŒ‰ç…§ä»Žæ˜“到难,一步步的解冟ë€?/p>

      ½W¬ä¸€æ­¥ï¼Œž®±æ˜¯ä¿®æ”¹JVM启动参数åQŒç›´æŽ¥å¢žåŠ å†…å­˜ã€‚è¿™ä¸€ç‚¹çœ‹ä¸ŠåŽ»ä¼ég¹Žå¾ˆç®€å•,但很å®ÒŽ(gu¨©)˜“被忽略。JVMé»˜è®¤å¯ä»¥ä½¿ç”¨çš„å†…å­˜äØ“(f¨´)64MåQŒTomcaté»˜è®¤å¯ä»¥ä½¿ç”¨çš„å†…å­˜äØ“(f¨´)128MBåQŒå¯¹äºŽç¨å¤æ‚一点的¾pȝ»Ÿž®×ƒ¼š(x¨¬)不够用。在某项目中åQŒå°±å› äØ“(f¨´)启动参数使用的默认å€û|¼Œ¾lå¸¸æŠ?#8220;OutOfMemory”错误。因此,-XmsåQ?Xmx参数一定不要忘记加ã€?/p>

      ½W¬äºŒæ­¥ï¼Œ‹‚€(g¨¨)查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。在一个项目中åQŒä‹É用两个数据库˜qžæŽ¥åQŒå…¶ä¸­ä¸“用于发送短信的数据库连接ä‹É用DBCP˜qžæŽ¥æ± ç®¡ç†ï¼Œç”¨æˆ·ä¸ÞZ¸ž®†çŸ­ä¿¡å‘出,有意ž®†æ•°æ®åº“˜qžæŽ¥ç”¨æˆ·åæ”¹é”™ï¼Œä½¿å¾—日志中有许多数据库连接异常的日志åQŒä¸€ŒD‰|—¶é—´åŽåQŒå°±å‡ºçް“OutOfMemory”错误。经分析åQŒè¿™æ˜¯ç”±äºŽDBCP˜qžæŽ¥æ± BUG引è“v的,数据库连接不上后åQŒæ²¡æœ‰å°†˜qžæŽ¥é‡Šæ”¾åQŒæœ€¾lˆä‹Éå¾—DBCPæŠ?#8220;OutOfMemory”错误。经˜q‡ä¿®æ”ÒŽ(gu¨©)­£¼‹®æ•°æ®åº“˜qžæŽ¥å‚数后,ž®±æ²¡æœ‰å†å‡ºçŽ°å†…å­˜æº¢å‡ºçš„é”™è¯¯ã€?/p>

      查看日志对于分析内存溢出是非帔R‡è¦çš„åQŒé€šè¿‡ä»”细查看日志åQŒåˆ†æžå†…存溢出前做过哪些操作åQŒå¯ä»¥å¤§è‡´å®šä½æœ‰é—®é¢˜çš„æ¨¡å—ã€?/p>

      ½W¬ä¸‰æ­¥ï¼Œå®‰æŽ’有经验的¾~–程人员对代码进行走查和分析åQŒæ‰¾å‡ºå¯èƒ½å‘生内存溢出的位置。重ç‚ÒŽ(gu¨©)Ž’æŸ¥ä»¥ä¸‹å‡ ç‚¹ï¼š(x¨¬)

      l         ‹‚€(g¨¨)查代码中是否有死循环或递归调用ã€?/p>

      l         ‹‚€(g¨¨)查是否有大åó@环重复äñ”生新对象实体ã€?/p>

      l         ‹‚€(g¨¨)查对数据库查询中åQŒæ˜¯å¦æœ‰ä¸€‹Æ¡èŽ·å¾—å…¨éƒ¨æ•°æ®çš„æŸ¥è¯¢ã€‚ä¸€èˆ¬æ¥è¯ß_(d¨¢)¼Œå¦‚果一‹Æ¡å–十万条记录到内存åQŒå°±å¯èƒ½å¼•è“v内存溢出。这个问题比较隐蔽,在上¾U¿å‰åQŒæ•°æ®åº“中数据较?y¨­u)®‘,不容易出问题åQŒä¸Š¾U¿åŽåQŒæ•°æ®åº“中数据多äº?ji¨£n),一‹Æ¡æŸ¥è¯¢å°±æœ‰å¯èƒ½å¼•起内存溢出。因此对于数据库查询ž®½é‡é‡‡ç”¨åˆ†é¡µçš„æ–¹å¼æŸ¥è¯¢ã€?/p>

      l         ‹‚€(g¨¨)查List、MAP½{‰é›†åˆå¯¹è±¡æ˜¯å¦æœ‰ä½¿ç”¨å®ŒåŽåQŒæœªæ¸…除的问题。List、MAP½{‰é›†åˆå¯¹è±¡ä¼š(x¨¬)始终存有对对象的引用åQŒä‹É得这些对象不能被GC回收ã€?/p>

      ½W¬å››æ­¥ï¼Œä½¿ç”¨å†…存查看工具动æ€?span style="background-color: yellow; color: #ee6600" id="Mark">查看内存使用情况。某个项目上¾U¿åŽåQŒæ¯‹Æ¡ç³»¾lŸå¯åŠ¨ä¸¤å¤©åŽåQŒå°±ä¼?x¨¬)出现内存溢出的错误。这¿Uæƒ…况一般是代码中出çŽîCº†(ji¨£n)¾~“慢的内存泄漏,用上面三个步骤解决不äº?ji¨£n),˜q™å°±éœ€è¦ä‹É用内å­?span style="background-color: yellow; color: #ee6600" id="Mark">查看工具äº?ji¨£n)ã€?/p>

      内存查看工具有许多,比较有名的有åQšOptimizeit Profiler、JProbe Profiler、JinSightå’ŒJava1.5çš„Jconsole½{‰ã€‚它们的基本工作原理大同ž®å¼‚åQŒéƒ½æ˜¯ç›‘‹¹‹Java½E‹åº˜qè¡Œæ—¶æ‰€æœ‰å¯¹è±¡çš„甌™¯·ã€é‡Šæ”„¡­‰åŠ¨ä½œåQŒå°†å†…å­˜½Ž¡ç†çš„æ‰€æœ‰ä¿¡æ¯è¿›è¡Œç»Ÿè®¡ã€åˆ†æžã€å¯è§†åŒ–。开发äh员可以根据这些信息判断程序是否有内存泄漏问题。一般来è¯ß_(d¨¢)¼Œä¸€ä¸ªæ­£å¸¸çš„¾pȝ»Ÿåœ¨å…¶å¯åŠ¨å®ŒæˆåŽå…¶å†…å­˜çš„å ç”¨é‡æ˜¯åŸºæœ¬ç¨³å®šçš„åQŒè€Œä¸åº”该是无限制的增长的。持¾l­åœ°è§‚察¾pȝ»Ÿ˜qè¡Œæ—¶ä‹É用的内存的大ž®ï¼Œå¯ä»¥çœ‹åˆ°åœ¨å†…å­˜ä‹É用监控窗口中是基本规则的锯é‹É形的囄¡º¿åQŒå¦‚果内存的大小持箋地增长,则说明系¾lŸå­˜åœ¨å†…存泄漏问题。通过间隔一ŒD‰|—¶é—´å–一‹Æ¡å†…存快照,然后对内存快照中对象的ä‹É用与引用½{‰ä¿¡æ¯è¿›è¡Œæ¯”对与分析åQŒå¯ä»¥æ‰¾å‡ºæ˜¯å“ªä¸ª¾cȝš„对象在泄漏ã€?/p>

      通过以上四个步骤的分析与处理åQŒåŸºæœ¬èƒ½å¤„理内存溢出的问题。当ç„?d¨°ng)ž¼Œåœ¨è¿™äº›è¿‡½E‹ä¸­ä¹Ÿéœ€è¦ç›¸å½“çš„¾léªŒä¸Žæ•æ„Ÿåº¦åQŒéœ€è¦åœ¨å®žé™…的开发与调试˜q‡ç¨‹ä¸­ä¸æ–­ç§¯ç´¯ã€?/p>

      æ€ÖM½“上来è¯ß_(d¨¢)¼Œäº§ç”Ÿå†…存溢出是由于代码写的不好造成的,因此提高代码的质量是最æ ÒŽ(gu¨©)œ¬çš„解军_Šžæ³•ã€‚æœ‰çš„ähè®¤äØ“(f¨´)先把功能实现åQŒæœ‰BUG时再在测试阶ŒDµè¿›è¡Œä¿®æ­£ï¼Œ˜q™ç§æƒÏx³•是错误的。正如一件äñ”品的质量是在生äñ”刉™€ çš„˜q‡ç¨‹ä¸­å†³å®šçš„åQŒè€Œä¸æ˜¯è´¨é‡æ£€‹¹‹æ—¶å†›_®šçš„,软äšg的质量在设计与编码阶ŒDµå°±å·²ç»å†›_®šäº?ji¨£n),‹¹‹è¯•只是对èÊYä»¶è´¨é‡çš„ä¸€ä¸ªéªŒè¯ï¼Œå› äØ“(f¨´)‹¹‹è¯•不可能找å‡?gu¨®)™ÊY件中所有的BUGã€?/p>

       

      --------------------------------------------------------------------------------------------------------------------------------

       

      原因有很多种åQŒæ¯”如:(x¨¬)

      1.数据量过于庞大;æ­Õdó@çŽ?åQ›é™(r¨´n)态变量和é?r¨´n)态方法过多;递归åQ›æ— æ³•确定是否被引用的对象;

      2.虚拟æœÞZ¸å›žæ”¶å†…å­˜åQˆå†…存泄漏)(j¨ª)åQ?/p>

          说白äº?ji¨£n)就是程序运行要用到的内存大于虚拟机能提供的最大内存就发生内存溢出äº?ji¨£n)ã€?内存溢出的问题要看业务和¾pȝ»Ÿå¤§å°è€Œå®šåQŒå¯¹äºŽæŸäº›ç³»¾lŸå¯èƒ½å†…存溢å‡ÞZ¸å¸¸è§åQŒä½†æŸäº›¾pȝ»Ÿ˜q˜æ˜¯å¾ˆå¸¸è§çš„解决的方法,

      一个是优化½E‹åºä»£ç åQŒå¦‚果业务庞大,逻辑复杂åQŒå°½é‡å‡ž®‘全局变量的引用,让程序ä‹É用完变量的时候释放该引用能够让垃圑֛žæ”¶å™¨å›žæ”¶åQŒé‡Šæ”¾èµ„源ã€?br />二就是物理解冻I¼Œå¢žå¤§ç‰©ç†å†…å­˜åQŒç„¶åŽé€šè¿‡åQ?Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m的修æ”?/p>

      一、内存溢出类�/font>
      1 �java.lang.OutOfMemoryError: PermGen space

      JVM ½Ž¡ç†ä¸¤ç§¾cÕdž‹çš„内存,堆和非堆。堆是给开发äh员用的上面说的就是,是在 JVM 启动时创建;非堆是留¾l?JVM 自己用的åQŒç”¨æ¥å­˜æ”„¡±»çš„信息的。它和堆不同åQŒè¿è¡ŒæœŸå†?GC 不会(x¨¬)释放½Iºé—´ã€‚如æž?web app 用了(ji¨£n)大量的第三方 jar 或者应用有太多çš?class æ–‡äšg而恰å¥?MaxPermSize 讄¡½®è¾ƒå°åQŒè¶…å‡ÞZº†(ji¨£n)也会(x¨¬)坯D‡´˜q™å—内存的占用过多造成溢出åQŒæˆ–è€?tomcat 热部¾|²æ—¶ä¾¯ä¸ä¼?x¨¬)清理前面加载的环境åQŒåªä¼?x¨¬)å°?context 更改为新部çÖv的,非堆存的内容ž®×ƒ¼š(x¨¬)­‘Šæ¥­‘Šå¤šã€?/p>

      2 �java.lang.OutOfMemoryError: Java heap space

      ½W¬ä¸€¿Uæƒ…冉|˜¯ä¸ªè¡¥å……,主要存在问题ž®±æ˜¯å‡ºçŽ°åœ¨è¿™ä¸ªæƒ…å†µä¸­ã€‚å…¶é»˜è®¤½Iºé—´ ( å?-Xms) 是物理内存的 1/64 åQŒæœ€å¤§ç©ºé—?(-Xmx) 是物理内存的 1/4 。如果内存剩余不åˆ?40 åQ…, JVM ž®×ƒ¼š(x¨¬)增大堆到 Xmx 讄¡½®çš„å€û|¼Œå†…存剩余­‘…过 70 åQ…, JVM ž®×ƒ¼š(x¨¬)减小堆到 Xms 讄¡½®çš„倹{€‚所以服务器çš?Xmx å’?Xms 讄¡½®ä¸€èˆ¬åº”该设¾|®ç›¸åŒé¿å…æ¯‹Æ?GC 后都要调整虚拟机堆的大小。假讄¡‰©ç†å†…存无限大åQŒé‚£ä¹?JVM å†…å­˜çš„æœ€å¤§å€ÆD·Ÿæ“ä½œ¾pȝ»Ÿæœ‰å…³åQŒä¸€èˆ?32 位机æ˜?1.5g åˆ?3g 之间åQŒè€?64 位的ž®×ƒ¸ä¼?x¨¬)有限制了(ji¨£n)ã€?/p>

      注意åQšå¦‚æž?Xms ­‘…过äº?Xmx å€û|¼Œæˆ–者堆最大值和非堆最大值的æ€Õd’Œ­‘…过äº?ji¨£n)物理内存或者操作系¾lŸçš„æœ€å¤§é™åˆ‰™ƒ½ä¼?x¨¬)引èµähœåŠ¡å™¨å¯åŠ¨ä¸è“v来ã€?/p>

      垃圾回收 GC 的角�/p>

      JVM 调用 GC 的频度还是很高的åQŒä¸»è¦ä¸¤¿Uæƒ…况下˜q›è¡Œåžƒåœ¾å›žæ”¶åQ?/p>

      当应用程序线½E‹ç©ºé—ÔŒ¼›å¦ä¸€ä¸ªæ˜¯ java 内存堆不­‘Ïx—¶åQŒä¼š(x¨¬)不断调用 GC åQŒè‹¥˜qžç®‹å›žæ”¶éƒ½è§£å†³ä¸äº?ji¨£n)内存堆不èƒö的问题时åQŒå°±ä¼?x¨¬)æŠ?out of memory é”™è¯¯ã€‚å› ä¸ø™¿™ä¸ªå¼‚常根据系¾lŸè¿è¡ŒçŽ¯å¢ƒå†³å®šï¼Œæ‰€ä»¥æ— æ³•é¢„æœŸå®ƒä½•æ—¶å‡ºçŽ°ã€?/p>

      æ ÒŽ(gu¨©)® GC 的机åˆÓž¼Œ½E‹åºçš„运行会(x¨¬)引è“v¾pȝ»Ÿ˜qè¡ŒçŽ¯å¢ƒçš„å˜åŒ–ï¼Œå¢žåŠ  GC 的触发机ä¼?x¨¬)ã€?/p>

      ä¸ÞZº†(ji¨£n)避免˜q™äº›é—®é¢˜åQŒç¨‹åºçš„设计和编写就应避免垃圑֯¹è±¡çš„内存占用å’?GC 的开销。显½Cø™°ƒç”?System.GC() åªèƒ½å»ø™®® JVM 需要在内存中对垃圾对象˜q›è¡Œå›žæ”¶åQŒä½†ä¸æ˜¯å¿…须马上回收åQ?/p>

      一个是òq¶ä¸èƒ½è§£å†›_†…存资源耗空的局面,另外也会(x¨¬)增加 GC 的消耗ã€?/p>

      二ã€?JVM 内存区域¾l„成
      ½Ž€å•çš„è¯?java中的堆和æ ?/p>

      java把内存分两种åQšä¸€¿Uæ˜¯æ ˆå†…存,另一¿Uæ˜¯å †å†…å­?/p>

      1。在函数中定义的基本¾cÕdž‹å˜é‡å’Œå¯¹è±¡çš„引用变量都在函数的栈内存中分配;

      2。堆内存用来存放�new创徏的对象和数组

      在函敎ͼˆä»£ç å—)(j¨ª)中定义一个变量时åQ?javaž®±åœ¨æ ˆä¸­ä¸ø™¿™ä¸ªå˜é‡åˆ†é…å†…存空é—ß_(d¨¢)¼Œå½“è¶…˜q‡å˜é‡çš„作用域后åQ?javaä¼?x¨¬)è‡ªåŠ¨é‡Šæ”¾æŽ‰ä¸ø™¯¥å˜é‡æ‰€åˆ†é…çš„内存空é—ß_(d¨¢)¼›åœ¨å †ä¸­åˆ†é…çš„内存ç”?java虚拟机的自动垃圾回收器来½Ž¡ç†

      堆的优势是可以动态分配内存大ž®ï¼Œç”Ÿå­˜æœŸä¹Ÿä¸å¿…事先告诉¾~–è¯‘å™¨ï¼Œå› äØ“(f¨´)它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢åQ?/p>

      栈的优势是存取速度比堆要快åQŒç¼ºç‚ÒŽ(gu¨©)˜¯å­˜åœ¨æ ˆä¸­çš„æ•°æ®å¤§ž®ä¸Žç”Ÿå­˜æœŸå¿…™åÀL˜¯¼‹®å®šçš„æ— ç‰|´» 性ã€?/p>

      java 堆分ä¸ÞZ¸‰ä¸ªåŒºåQ?New ã€?Old å’?Permanent

      GC 有两个线½E‹ï¼š(x¨¬)

      新创建的对象被分配到 New åŒºï¼Œå½“è¯¥åŒø™¢«å¡«æ»¡æ—¶ä¼š(x¨¬)è¢?GC 辅助¾U¿ç¨‹¿UÕdˆ° Old 区,å½?Old åŒÞZ¹Ÿå¡«æ»¡äº?ji¨£n)ä¼?x¨¬)触发 GC ä¸Èº¿½E‹éåŽ†å †å†…å­˜é‡Œçš„æ‰€æœ‰å¯¹è±¡ã€?Old 区的大小½{‰äºŽ Xmx 减去 -Xmn

      java栈存�/p>

      栈调æ•ß_(d¨¢)¼š(x¨¬)参数æœ?+UseDefaultStackSize -Xss256KåQŒè¡¨½Cºæ¯ä¸ªçº¿½E‹å¯ç”Œ™¯· 256k的栈½Iºé—´

      每个¾U¿ç¨‹éƒ½æœ‰ä»–自å·Þqš„ Stack

      三ã€?JVM如何讄¡½®è™šæ‹Ÿå†…å­˜
      提示åQšåœ¨ JVM中如æž?98åQ…的旉™—´æ˜¯ç”¨äº?GC且可用的 Heap size 不èƒö 2åQ…çš„æ—¶å€™å°†æŠ›å‡ºæ­¤å¼‚å¸æ€¿¡æ¯ã€?/p>

      提示åQ?Heap Size 最大不要超˜q‡å¯ç”¨ç‰©ç†å†…存的 80åQ…,一般的要将 -Xmså’?-Xmx选项讄¡½®ä¸ºç›¸åŒï¼Œè€?-Xmnä¸?1/4çš?-Xmx倹{€?/p>

      提示åQ?JVM初始分配的内存由 -Xms指定åQŒé»˜è®¤æ˜¯ç‰©ç†å†…å­˜çš?1/64åQ?JVM最大分配的内存ç”?-Xmx指定åQŒé»˜è®¤æ˜¯ç‰©ç†å†…å­˜çš?1/4ã€?/p>

      默认½IÞZ½™å †å†…存小äº?40%æ—Óž¼Œ JVMž®×ƒ¼š(x¨¬)增大堆直åˆ?-Xmx的最大限åˆÓž¼›½IÞZ½™å †å†…存大äº?70%æ—Óž¼Œ JVMä¼?x¨¬)减ž®‘堆直åˆ?-Xms的最ž®é™åˆ¶ã€‚因此服务器一般设¾|?-Xmsã€?-Xmx相等以避免在每次 GC 后调整堆的大ž®ã€?/p>

      提示åQšå‡è®„¡‰©ç†å†…存无限大的话åQ?JVMå†…å­˜çš„æœ€å¤§å€ÆD·Ÿæ“ä½œ¾pȝ»Ÿæœ‰å¾ˆå¤§çš„关系ã€?/p>

      ½Ž€å•的说就 32位处理器虽然可控内存½Iºé—´æœ?4GB,但是具体的操作系¾lŸä¼š(x¨¬)¾l™ä¸€ä¸ªé™åˆÓž¼Œ

      ˜q™ä¸ªé™åˆ¶ä¸€èˆ¬æ˜¯ 2GB-3GBåQˆä¸€èˆ¬æ¥è¯?Windows¾pȝ»Ÿä¸‹äØ“(f¨´) 1.5G-2GåQ?Linux¾pȝ»Ÿä¸‹äØ“(f¨´) 2G-3GåQ‰ï¼Œ è€?64bit以上的处理器ž®×ƒ¸ä¼?x¨¬)有限制ä?/p>

      提示åQšæ³¨æ„ï¼š(x¨¬)如果 Xms­‘…过äº?Xmxå€û|¼Œæˆ–者堆最大值和非堆最大值的æ€Õd’Œ­‘…过äº?ji¨£n)物理å†?存或者操作系¾lŸçš„æœ€å¤§é™åˆ‰™ƒ½ä¼?x¨¬)引èµähœåŠ¡å™¨å¯åŠ¨ä¸è“v来ã€?/p>

      提示åQšè®¾¾|?NewSizeã€?MaxNewSize相等åQ?“new”的大ž®æœ€å¥½ä¸è¦å¤§äº?“old”的一半,原因æ˜?old区如果不够大ä¼?x¨¬)频¾Jçš„触发 “ä¸?” GC åQŒå¤§å¤§é™ä½Žäº†(ji¨£n)性能

      JVM使用 -XX:PermSize讄¡½®éžå †å†…存初始å€û|¼Œé»˜è®¤æ˜¯ç‰©ç†å†…存的 1/64åQ?/p>

      ç”?XX:MaxPermSize讄¡½®æœ€å¤§éžå †å†…存的大小åQŒé»˜è®¤æ˜¯ç‰©ç†å†…å­˜çš?1/4ã€?/p>

      解决æ–ÒŽ(gu¨©)³•åQšæ‰‹åŠ¨è®¾¾|?Heap size

      修改 TOMCAT_HOME/bin/catalina.bat

      åœ?#8220; echo “Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:(x¨¬)

      1. JAVA_OPTS=”-server -Xms800m -Xmx800m -XX:MaxNewSize=256m”   

      四、性能‹‚€(g¨¨)查工具ä‹Éç”?/font>
      定位内存泄漏åQ?/p>

      JProfiler 工具主要用于‹‚€(g¨¨)查和跟踪¾pȝ»ŸåQˆé™äº?Java 开发的åQ‰çš„æ€§èƒ½ã€?JProfiler 可以通过时时的监控系¾lŸçš„内存使用情况åQŒéšæ—¶ç›‘视垃圑֛žæ”Óž¼Œ¾U¿ç¨‹˜qè¡Œçж况½{‰æ‰‹ŒDµï¼Œä»Žè€Œå¾ˆå¥½çš„监视 JVM ˜qè¡Œæƒ…况å?qi¨¢ng)其性能ã€?/p>


      1. 应用服务器内存长期不合理占用åQŒå†…存经常处于高位占用,很难回收åˆîC½Žä½ï¼›

      2. 应用服务器极ä¸ÞZ¸½E›_®šåQŒå‡ ä¹Žæ¯ä¸¤å¤©é‡æ–°å¯åЍ䏀‹Æ¡ï¼Œæœ‰æ—¶ç”šè‡³æ¯å¤©é‡æ–°å¯åЍ䏀‹Æ¡ï¼›

      3. 应用服务器经常做 Full GC(Garbage Collection)åQŒè€Œä¸”æ—‰™—´å¾ˆé•¿åQŒå¤§¾U¦éœ€è¦?30-40¿U’,应用服务器在å?Full GC的时候是不响应客æˆïL(f¨¥ng)š„交易è¯äh±‚的,非常影响¾pȝ»Ÿæ€§èƒ½ã€?/p>

      因䨓(f¨´)开发环境和产品环境ä¼?x¨¬)有不同åQŒå¯¼è‡´è¯¥é—®é¢˜å‘生有时ä¼?x¨¬)在产品环境中发生ï¼?通常可以使用工具跟踪¾pȝ»Ÿçš„内存ä‹É用情况,在有些个别情况下或许某个时刻¼‹®å®ž 是ä‹É用了(ji¨£n)å¤§é‡å†…å­˜å¯ÆD‡´ out of memoryåQŒè¿™æ—¶åº”¾l§ç®‹è·Ÿè¸ªçœ‹æŽ¥ä¸‹æ¥æ˜¯å¦ä¼?x¨¬)有下降åQ?/p>

      如果一直居高不下这肯定ž®±å› ä¸ºç¨‹åºçš„åŽŸå› å¯ÆD‡´å†…存泄漏ã€?/p>

      五、不健壮代码的特征及(qi¨¢ng)解决办法
      1 、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动讄¡½®ä¸?null åQŒæš—½Cºåžƒåœ¾æ”¶é›†å™¨æ¥æ”¶é›†è¯¥å¯¹è±¡åQŒé˜²æ­¢å‘生内存泄霌Ӏ?/p>

      对于仍然有指针指向的实例åQ?jvm ž®×ƒ¸ä¼?x¨¬)回收该资æº?, 因䨓(f¨´)垃圾回收ä¼?x¨¬)å°†å€égØ“(f¨´) null 的对象作为垃圾,提高 GC 回收机制效率åQ?/p>

      2 、我们的½E‹åºé‡Œä¸å¯é¿å…å¤§é‡ä‹É用字½W¦ä¸²å¤„理åQŒé¿å…ä‹Éç”?String åQŒåº”大量使用 StringBuffer åQŒæ¯ä¸€ä¸?String 对象都得独立占用内存一块区域;

      1. String str = “aaa”;   
      2.   
      3. String str2 = “bbb”;   
      4.   
      5. String str3 = str + str2;// 假如执行此次之后 str ,str2 以后再不被调ç”?, 那它?y¨­u)®×ƒ¼?x¨¬)被放在内存中½{‰å¾… Java çš?gc åŽÕd›žæ”?, ½E‹åºå†…过多的出现˜q™æ ·çš„æƒ…况就ä¼?x¨¬)报上面的那个错è?, 廸™®®åœ¨ä‹É用字½W¦ä¸²æ—¶èƒ½ä½¿ç”¨ StringBuffer ž®×ƒ¸è¦ç”¨ String, ˜q™æ ·å¯ä»¥çœä¸ž®‘开销åQ?  

      3 、尽量少用静(r¨´n)æ€å˜é‡ï¼Œå› äØ“(f¨´)é?r¨´n)态变量是全局的, GC 不会(x¨¬)回收的;

      4 、避免集中创建对象尤其是大对象, JVM ä¼?x¨¬)突焉™œ€è¦å¤§é‡å†…存,˜q™æ—¶å¿…ç„¶ä¼?x¨¬)触å?GC 优化¾pȝ»Ÿå†…存环境åQ›æ˜¾½Cºçš„声明数组½Iºé—´åQŒè€Œä¸”甌™¯·æ•°é‡˜q˜æžå¤§ã€?/p>

      ˜q™æ˜¯ä¸€ä¸ªæ¡ˆä¾‹æƒ³å®šä¾›å¤§å®¶è­¦æˆ’:

      使用jspsmartUpload作文件上ä¼?现在˜qè¡Œ˜q‡ç¨‹ä¸­ç»å¸¸å‡ºçްjava.outofMemoryError的错误,用top命ä×o(h¨´)看看˜q›ç¨‹ä½¿ç”¨æƒ…况åQŒå‘现内存不­‘?MåQŒèбäº?ji¨£n)很长时é—ß_(d¨¢)¼Œå‘现是jspsmartupload的问题。把jspsmartupload¾l„äšg的源码文ä»Óž¼ˆclassæ–‡äšgåQ‰å¾~–译成Javaæ–‡äšgåQŒå¦‚梦方醒:(x¨¬)

      1. m_totalBytes = m_request.getContentLength();        
      2. m_binArray = new byte[m_totalBytes];      

      变量m_totalBytes表示用户上传的文件的总长度,˜q™æ˜¯ä¸€ä¸ªå¾ˆå¤§çš„æ•°ã€‚如果用˜q™æ ·å¤§çš„æ•°åŽ»å£°æ˜Žä¸€ä¸ªbyte数组åQŒåƈ¾l™æ•°¾l„的每个元素分配内存½Iºé—´åQŒè€Œä¸”m_binArray数组不能马上被释放,JVM的垃圑֛žæ”¶ç¡®å®žæœ‰é—®é¢˜åQŒå¯¼è‡´çš„¾l“æžœž®±æ˜¯å†…存溢出ã€?/p>

      jspsmartUploadä¸ÞZ»€æœ«è¦˜q™æ ·ä½œï¼Œæœ‰ä»–的原因,æ ÒŽ(gu¨©)®RFC1867çš„http上传标准åQŒå¾—åˆîC¸€ä¸ªæ–‡ä»¶æµåQŒåƈ不知道文件流的长度。设计者如果想文äšg的长度,只有操作servletinputstream一‹Æ¡æ‰çŸ¥é“åQŒå› ä¸ÞZ“Q何流都不知道大小。只有知道文仉™•¿åº¦äº†(ji¨£n)åQŒæ‰å¯ä»¥é™åˆ¶ç”¨æˆ·ä¸Šä¼ æ–‡äšgçš„é•¿åº¦ã€‚äØ“(f¨´)äº?ji¨£n)省去这个麻烦(ch¨³),jspsmartUpload设计者直接在内存中打开文äšgåQŒåˆ¤æ–­é•¿åº¦æ˜¯å¦ç¬¦åˆæ ‡å‡†ï¼Œ½W¦åˆž®±å†™åˆ°æœåŠ¡å™¨çš„ç¡¬ç›˜ã€‚è¿™æ ·äñ”生内存溢出,˜q™åªæ˜¯æˆ‘的一个猜‹¹‹è€Œå·²ã€?/p>

      所以编½E‹çš„æ—¶å€™ï¼Œä¸è¦åœ¨å†…存中甌™¯·å¤§çš„½Iºé—´åQŒå› ä¸ºweb服务器的内存有限åQŒåƈ且尽可能的ä‹É用流操作åQŒä¾‹å¦?/p>

      1. byte[] mFileBody = new byte[512];   
      2.          Blob vField= rs.getBlob("FileBody");   
      3.       InputStream instream=vField.getBinaryStream();   
      4.       FileOutputStream fos=new FileOutputStream(saveFilePath+CFILENAME);   
      5.          int b;   
      6.                       while( (b =instream.read(mFileBody)) != -1){   
      7.                         fos.write(mFileBody,0,b);   
      8.                          }   
      9.         fos.close();   
      10.       instream.close();  

      5 、尽量运用对象池技术以提高¾pȝ»Ÿæ€§èƒ½åQ›ç”Ÿå‘½å‘¨æœŸé•¿çš„对象拥有生命周期短的对象时å®ÒŽ(gu¨©)˜“引发内存泄漏åQŒä¾‹å¦‚大集合对象拥有大数据量的业务对象的时候,可以考虑分块˜q›è¡Œå¤„理åQŒç„¶åŽè§£å†³ä¸€å—释放一块的½{–ç•¥ã€?/p>

      6 、不要在¾lå¸¸è°ƒç”¨çš„æ–¹æ³•中创徏对象åQŒå°¤å…¶æ˜¯å¿Œè®³åœ¨åó@环中创徏对象。可以适当的ä‹Éç”?hashtable åQ?vector 创徏一¾l„对象容器,然后从容器中åŽÕd–那些对象åQŒè€Œä¸ç”¨æ¯‹Æ?new 之后又丢å¼?/p>

      7 、一般都是发生在开启大型文件或跟数据库一‹Æ¡æ‹¿äº?ji¨£n)太多的数据åQŒé€ æˆ Out Of Memory Error 的状况,˜q™æ—¶ž®±å¤§æ¦‚要计算一下数据量的最大值是多少åQŒåƈ且设定所需最ž®åŠ(qi¨¢ng)最大的内存½Iºé—´å€¹{€?/p>



      ]]> Ö÷Õ¾Ö©Öë³ØÄ£°å£º ÷ºÓ¿ÚÊÐ| Àײ¨ÏØ| ÒËÖÝÊÐ| ÎÚÀ­ÌغóÆì| ÐËÒµÏØ| ÓÀÐÞÏØ| °à¸êÏØ| ÄÚ»ÆÏØ| Îä´¨ÏØ| ¹«°²ÏØ| ̨½­ÏØ| µ±ÐÛÏØ| ¶¨½áÏØ| ¹ðƽÊÐ| °×Ë®ÏØ| ºÍÆ½ÏØ| ´ïÖÝÊÐ| ·À³Ç¸ÛÊÐ| ¶«°¢ÏØ| »´±±ÊÐ| ¹âÔóÏØ| ½¡¿µ| ¸ßÌ¨ÏØ| ÓݳÇÏØ| Ðû³ÇÊÐ| ´ó³§| ÃàÖñÊÐ| ººÊÙÏØ| ÅíÑôÏØ| À¼¿¼ÏØ| ¿Ëʲ¿ËÌÚÆì| ͨµÀ| ºéÔóÏØ| лͨÃÅÏØ| ÕØ¶«ÊÐ| ÄÏÆ½ÊÐ| ÕòÔ¶ÏØ| ÃûÉ½ÏØ| ±¦¼¦ÊÐ| »ù¡ÊÐ| ÆÑ³ÇÏØ|