??xml version="1.0" encoding="utf-8" standalone="yes"?>在线播放一区,国产中文日韩欧美,精品亚洲成a人在线观看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规格描述解释器UL到特定的计算ZQ就能保证经q编译的MJava代码能够在该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源程序翻译ؓJVM可执行代?字节码。这一~译q程同C/C++ ?~译有些不同。当C~译器编译生成一个对象的代码Ӟ该代码是为在某一特定gq_q行而生的。因此,在编译过E中Q编译程序通过查表所有对W号的引 用{换ؓ特定的内存偏U量Q以保证E序q行。Java~译器却不将对变量和Ҏ的引用编译ؓ数值引用,也不定E序执行q程中的内存布局Q而是这些符?引用信息保留在字节码中,p释器在运行过E中创立内存布局Q然后再通过查表来确定一个方法所在的地址。这样就有效的保证了Java的可UL性和安全 性?/span>
  
   q行JVM字节码的工作是由解释器来完成的。解释执行过E分三部q行Q代码的装入、代码的校验和代码的执行。装入代码的工作?c装载器"Qclass loaderQ完成。类装蝲器负责装入运行一个程序需要的所有代码,q也包括E序代码中的cLl承的类和被其调用的cR当c装载器装入一个类Ӟ该类被放 在自q名字I间中。除了通过W号引用自己名字I间以外的类Q类之间没有其他办法可以影响其他cR在本台计算Z的所有类都在同一地址I间内,而所有从?部引q的c,都有一个自q立的名字I间。这使得本地c通过׃n相同的名字空间获得较高的q行效率Q同时又保证它们与从外部引进的类不会怺影响。当装入 了运行程序需要的所有类后,解释器便可确定整个可执行E序的内存布局。解释器为符号引用同特定的地址I间建立对应关系及查询表。通过在这一阶段定代码?内存布局QJava很好地解决了pcL变而子类崩溃的问题,同时也防止了代码对地址的非法访问?/span>
  
  随后Q被装入的代码由字节码校验器q行查。校验器可发现操作数栈溢出,非法数据cd转化{多U错误。通过校验后,代码便开始执行了?/span>
  
  Java字节码的执行有两U方式:
  1.x~译方式Q解释器先将字节码编译成机器码,然后再执行该机器码?/span>
  2.解释执行方式Q解释器通过每次解释q执行一段代码来完成Java字节码程 序的所有操作?/span>
  通常采用的是W二U方法。由于JVM规格描述h_的灵zL,q得将字节码翻译ؓ机器代码的工?/span>
  
  h较高的效率。对于那些对q行速度要求较高的应用程序,解释器可Java字节码即时编译ؓ机器码,从而很好地保证了Java代码的可UL性和高性能?/span>
  
  ?JVM规格描述 
   JVM的设计目标是提供一个基于抽象规格描q的计算机模型,释程序开发h员提很好的灵zL,同时也确保Java代码可在W合该规范的Mpȝ上运 行。JVM对其实现的某些方面给Z具体的定义,特别是对Java可执行代码,卛_节码(Bytecode)的格式给Z明确的规根{这一规格包括操作?和操作数的语法和数倹{标识符的数DC方式、以及JavacL件中的Java对象、常量缓冲池在JVM?/span>存储 映象。这些定义ؓJVM解释器开发h员提供了所需的信息和开发环境。Java的设计者希望给开发h员以随心所Ʋ用Java的自由?/span>
  
  JVM定义了控制Java代码解释执行和具体实现的五种规格Q它们是Q?/span>
  JVM指opȝ
  JVM寄存?/span>
  JVM栈结?/span>
  JVM片回收?/span>
  JVM存储 ?/span>
  
  2.1JVM指opȝ
  
   JVM指opȝ同其他计机的指令系l极其相伹{Java指o也是?操作码和操作C部分l成。操作码?位二q制敎ͼ操作数进紧随在操作码的后面,光度根据需要而不同。操作码用于指定一条指令操作的性质Q在q里我们?用汇~符L形式q行说明Q,如iload表示从存储器中装入一个整敎ͼanewarray表示Z个新数组分配I间Qiand表示两个整数? ?Qret用于程控制Q表CZҎ一Ҏ的调用中q回。当长度大于8位时Q操作数被分Z个以上字节存放。JVM采用?big endian"的编码方式来处理q种情况Q即高位bits存放在低字节中。这?Motorola及其他的RISC CPU采用的编码方式是一致的Q而与Intel采用?little endian "的编码方式即低位bits存放在低位字节的Ҏ不同?/span>
  
  Java指opȝ是以Java语言的实Cؓ目的设计的,其中包含了用于调用方法和监视多先E系l的指o。Java?位操作码的长度得JVM最多有256U指令,目前已用了160多种操作码?/span>
  
  2.2JVM指opȝ
  
   所有的CPU均包含用于保存系l状态和处理器所需信息的寄存器l。如果虚拟机定义较多的寄存器Q便可以从中得到更多的信息而不必对栈或内存q行讉KQ这 有利于提高运行速度。然而,如果虚拟Z的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,q反而会?低虚拟机的效率。针对这U情况,JVM只设|了4个最为常用的寄存器。它们是Q?/span>
  pcE序计数?/span>
  optop操作数栈指?/span>
  frame当前执行环境指针
  vars指向当前执行环境中第一个局部变量的指针
  所有寄存器均ؓ32位。pc用于记录E序的执行。optop,frame和vars用于记录指向Java栈区的指针?/span>
  
  2.3JVM栈结?/span>
  
  作ؓZ栈结构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后Q便代码中一个类的每一个方法创Z个栈框架Q以保存该方法的状态信息。每个栈框架包括以下三类信息Q?/span>
  局部变?/span>
  执行环境
  操作数栈
  
  局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量?/span>
   执行环境用于保存解释器对Java字节码进行解释过E中所需的信息。它们是Q上ơ调用的Ҏ、局部变量指针和操作数栈的栈和栈底指针。执行环境是一?执行一个方法的控制中心。例如:如果解释器要执行iadd(整数加法)Q首先要从frame寄存器中扑ֈ当前执行环境Q而后便从执行环境中找到操作数栈, 从栈弹Z个整数进行加法运,最后将l果压入栈顶?/span>
  操作数栈用于存储q算所需操作数及q算的结果?/span>
  
  2.4JVM片回收?/span>
  
  Javacȝ实例所需的存储空间是在堆上分配的。解释器具体承担为类实例分配I间的工作。解释器在ؓ一个实例分配完存储I间后,便开始记录对该实例所占用的内存区域的使用。一旦对象用完毕,便将其回收到堆中?/span>
   在Java语言中,除了new语句外没有其他方法ؓ一对象甌和释攑ֆ存。对内存q行释放和回收的工作是由Javaq行pȝ承担的。这允许Javaq行 pȝ的设计者自己决定碎片回收的Ҏ。在SUN公司开发的Java解释器和Hot Java环境中,片回收用后台线E的方式来执行。这不但行系l提供了良好的性能Q而且使程序设计h员摆׃自己控制内存使用的风险?/span>
  
  2.5JVM存储?/span>
  
   JVM有两cd储区Q常量缓冲池和方法区。常量缓冲池用于存储cdU、方法和字段名称以及串常量。方法区则用于存储JavaҎ的字节码。对于这两种?储区域具体实现方式在JVM规格中没有明规定。这使得Java应用E序的存储布局必须在运行过E中定Q依赖于具体q_的实现方式?/span>
  
  JVM是ؓJava字节码定义的一U独立于具体q_的规格描qͼ是Javaq_独立性的基础。目前的JVMq存在一些限制和不Q有待于q一步的完善Q但无论如何QJVM的思想是成功的?/span>
  
  Ҏ分析Q如果把Java原程序想象成我们?/span>C++ ?E序QJava原程序编译后生成的字节码q当于C++原程序编译后?0x86的机器码Q二q制E序文gQ,JVM虚拟机相当于80x86计算机系 l?Java解释器相当于80x86CPU。在80x86CPU上运行的是机器码Q在Java解释器上q行的是Java字节码?/span>
  
   Java解释器相当于q行Java字节码的“CPU”,但该“CPU”不是通过g实现的,而是用Y件实现的。Java解释器实际上是特定的^C的一 个应用程序。只要实C特定q_下的解释器程序,Java字节码就能通过解释器程序在该^Cq行Q这是Java跨^台的Ҏ。当前,q不是在所有的q_ 下都有相应Java解释器程序,q也是Javaq不能在所有的q_下都能运行的原因Q它只能在已实现了Java解释器程序的q_下运行?br />

       Java主要靠Java虚拟机(JVMQ在目标码实现q_无关性。JVM是一U抽象机器,它附着在具体操作系l之上,本nh一套虚机器指oQƈ有自q栈、寄存器l等。但JVM通常是在软g上而不是在g上实现。(目前QSUNpȝ公司已经设计实现了Java芯片Q主要用在|络计算机NC上。另外,Java芯片的出C会Java更容易嵌入到家用电器中。)JVM是Javaq_无关的基Q在JVM上,有一个Java解释器用来解释Java~译器编译后的程序。Java~程人员在编写完软g后,通过Java~译器将Java源程序编译ؓJVM的字节代码。Q何一台机器只要配备了Java解释器,可以运行这个程序,而不这U字节码是在何种q_上生成的Q过E如?所C)。另外,Java采用的是ZIEEE标准的数据类型。通过JVM保证数据cd的一致性,也确保了Java的^台无x?nbsp;

单说Qjava的解释器只是一个基于虚拟机jvmq_的程?nbsp;


abin 2015-03-23 15:23 发表评论
]]>
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;


abin 2015-03-23 00:01 发表评论
]]>
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优化E序性能而采取的Ҏ令进行重新排序执行的一U手Dc重排序分ؓ两类Q编译期重排序和q行期重排序Q分别对应编译时和运行时环境

在ƈ发程序中Q程序员会特别关注不同进E或U程之间的数据同步,特别是多个线E同时修改同一变量Ӟ必须采取可靠的同步或其它措施保障数据被正地修改Q这里的一条重要原则是Q不要假设指令执行的序Q你无法预知不同U程之间的指令会以何U顺序执行?/p>

但是在单U程E序中,通常我们Ҏ假设指o是顺序执行的Q否则可以想象程序会发生什么可怕的变化。理想的模型是:各种指o执行的顺序是唯一且有序的Q这个顺序就是它们被~写在代码中的顺序,与处理器或其它因素无养Iq种模型被称作顺序一致性模型,也是Z?#183;Zgpȝ模型。当Ӟq种假设本n是合理的Q在实践中也鲜有异常发生Q但事实上,没有哪个C多处理器架构会采用这U模型,因ؓ它是在是太低效了。而在~译优化和CPU水U中Q几乎都涉及到指令重排序?/p>

~译期重排序

~译期重排序的典型就是通过调整指o序Q在不改变程序语义的前提下,可能减寄存器的读取、存储次敎ͼ充分复用寄存器的存储倹{?/p>

假设W一条指令计一个Dl变量Aq存攑֜寄存器中Q第二条指o与A无关但需要占用寄存器Q假讑֮占用A所在的那个寄存器)Q第三条指o使用A的g与第二条指o无关。那么如果按照顺序一致性模型,A在第一条指令执行过后被攑օ寄存器,在第二条指o执行时A不再存在Q第三条指o执行时A重新被读入寄存器Q而这个过E中QA的值没有发生变化。通常~译器都会交换第二和W三条指令的位置Q这L一条指令结束时A存在于寄存器中,接下来可以直接从寄存器中dA的|降低了重复读取的开销?br />
重排序对于流水线的意?/strong>

CCPU几乎都采用流水线机制加快指o的处理速度Q一般来_一条指令需要若q个CPU旉周期处理Q而通过水Uƈ行执行,可以在同{的旉周期内执行若q条指oQ具体做法简单地说就是把指o分ؓ不同的执行周期,例如d、寻址、解析、执行等步骤Qƈ攑֜不同的元件中处理Q同时在执行单元EU中,功能单元被分Z同的元gQ例如加法元件、乘法元件、加载元件、存储元件等Q可以进一步实C同的计算q行执行?/p>

水U架构决定了指o应该被ƈ行执行,而不是在序化模型中所认ؓ的那栗重排序有利于充分用流水线Q进而达到超标量的效果?br />
保序?/strong>

管指o在执行时q不一定按照我们所~写的顺序执行,但毋庸置疑的是,在单U程环境下,指o执行的最l效果应当与其在序执行下的效果一_否则q种优化便会失去意义?/p>

通常无论是在~译期还是运行期q行的指令重排序Q都会满上面的原则?/p>

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

在Java存储模型QJava Memory Model, JMMQ中Q重排序是十分重要的一节,特别是在q发~程中。JMM通过happens-before法则保证序执行语义Q如果想要让执行操作B的线E观察到执行操作A的线E的l果Q那么A和B必Lhappens-before原则Q否则,JVM可以对它们进行Q意排序以提高E序性能?/p>

volatile关键字可以保证变量的可见性,因ؓ对volatile的操作都在Main Memory中,而Main Memory是被所有线E所׃n的,q里的代价就是牺牲了性能Q无法利用寄存器或CacheQ因为它们都不是全局的,无法保证可见性,可能产生脏读?/p>

volatileq有一个作用就是局部阻止重排序的发生,对volatile变量的操作指令都不会被重排序Q因为如果重排序Q又可能产生可见性问题?/p>

在保证可见性方面,锁(包括昑ּ锁、对象锁Q以及对原子变量的读写都可以保变量的可见性。但是实现方式略有不同,例如同步锁保证得到锁时从内存里重新读入数据刷新缓存,释放锁时数据写回内存以保数据可见,而volatile变量q脆都是d内存?/p>







abin 2015-03-22 13:27 发表评论
]]>
重排序、内存可见性、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ؓ了更好的理解 ConcurrentHashMapQ让我们首先来了解一?Java 的内存模型?/p>

Java 语言的内存模型由一些规则组成,q些规则定U程对内存的讉K如何排序以及何时可以保它们对线E是可见的。下面我们将分别介绍 Java 内存模型的重排序Q内存可见性和 happens-before 关系?/p>

重排?/h3>

内存模型描述了程序的可能行ؓ。具体的~译器实现可以生Q意它喜欢的代?-- 只要所有执行这些代码生的l果Q能够和内存模型预测的结果保持一致。这为编译器实现者提供了很大的自由,包括操作的重排序?/p>

~译器生成指令的ơ序Q可以不同于源代码所暗示?#8220;昄”版本。重排序后的指oQ对于优化执行以及成熟的全局寄存器分配算法的使用Q都是大有脾益的Q它使得E序在计性能上有了很大的提升?/p>

重排序类型包括:

  • ~译器生成指令的ơ序Q可以不同于源代码所暗示?#8220;昄”版本?/li>
  • 处理器可以ؕ序或者ƈ行的执行指o?/li>
  • ~存会改变写入提交到d存的变量的次序?/li>

内存可见?/h3>

׃C可共享内存的多处理器架构可能D一个线E无法马上(甚至永远Q看到另一个线E操作生的l果。所?Java 内存模型规定?JVM 的一U最保证:什么时候写入一个变量对其他U程可见?/p>

在现代可׃n内存的多处理器体pȝ构中每个处理器都有自q~存Qƈ周期性的与主内存协调一致。假讄E?A 写入一个变量?VQ随后另一个线E?B d变量 V 的|在下列情况下Q线E?B d的值可能不是线E?A 写入的最新|

  • 执行U程 A 的处理器把变?V ~存到寄存器中?/li>
  • 执行U程 A 的处理器把变?V ~存到自q~存中,但还没有同步hC内存中去?/li>
  • 执行U程 B 的处理器的缓存中有变?V 的旧倹{?/li>

Happens-before 关系

happens-before 关系保证Q如果线E?A 与线E?B 满 happens-before 关系Q则U程 A 执行动作的结果对于线E?B 是可见的。如果两个操作未?happens-before 排序QJVM 可以对他们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. 传递性:如果 A happens-before ?BQ且 B happens-before CQ则 A happens-before C?/li>


abin 2015-03-22 12:40 发表评论
]]>
探秘Java 7新增垃圾回收器G1Ҏ?/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垃圾回收器(UG1 GCQ是JDK 7中Java HotSpot VM新引入的垃圾回收器,Java SE 6 Update 14中已l包含了一个G1的体验版本(?1CTO之前的报|在Java SE 6 u14?月初dӞ原本Sun的声明是QG1垃圾回收器需要收Ҏ能用。然而之后不久,Sun表示q是一个误会,修改了原本的发布声明Qƈ表示现在以及来对G1的用都是完全免费的Q,G1是设计用于替代HotSpot低gq的q行标记/清除垃圾回收器(也叫做CMSQ的?/div><div></div><div>Java 7 G1属?/div><div></div><div>G1是一个服务端垃圾回收器,有以下属性:</div><div></div><div>◆q行和ƈ发性:G1利用了当今硬件中存在的ƈ行性,当Java应用E序的线E被停止Ӟ它用所有可用的CPUQ核心,gU程{)加速其停止Q在停止q程中运行JavaU程最化整个堆栈?/div><div></div><div>◆代:和其他HotSpot GC一PG1是一代,意味着它在处理新分配的对象Q年MQ和已经生存了一D|间的对象Q年老代Q时会不同,它主要集中于新对象上的垃圑֛收活动,因ؓ它们是最可能回收的,旧对象只是偶访问一下,对于大多数Java应用E序Q代的垃圑֛收对于替代方案具有重要优ѝ?/div><div></div><div>◆压羃Q和CMS不同QG1会随旉推移对堆栈进行压~,压羃消除了潜在的片问题Q确保长旉q行的操作流畅和一致?/div><div></div><div>◆可预性:G1比CMS预测性更佻Iq都是由于消除了片问题带来的好处,再也没有CMS中停止期间出现的负面影响Q另外,G1有一个暂停预模型,允许它满I或很超q)暂停旉目标?/div><div></div><div>Java 7 G1描述</div><div></div><div>和其它HotSpot GC相比QG1采用了一个非怸同的堆栈布局ҎQ在G1中,q轻代和q老代之间没有物理隔离Q相反,它们之间有一个连l的堆栈Q被分成大小一L区域QregionQ,q轻代可能是一套非q箋的区域,q老代也一Pq就允许G1在年M和年老代之间灉|地移动资源?/div><div></div><div>G1中的回收是通过消除暂停发生的,在此期间Q幸存者指的是回收集被转移到另一个区域,以便回收区域可以再生Q消除暂停是q行的,所有可用的CPU都会参加Q大多数消除暂停攉可用的年d域,和其它HotSpot GC中的q轻回收是一LQ在暂停期间偶尔也会选择q老区域回Ӟ因ؓG1在年M代回收上q肩负了q老代的回收活动?/div><div></div><div>和CMS相同的是QG1会定期执行一个ƈ发标记暂停,q个阶段的主要职责是识别哪一个年老区域的垃圾对象是最完整的,因ؓq些是最有效和最值得回收的,和CMS不同的是QG1不会执行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讄一个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>注意上面两个选项表示的目标,没有承诺和保证,在某些情况下它们可能能够工作QGC不是L能够执行它们?/div><div></div><div>另外Q年M的大可以明指定媄响消除暂停时_</div><div></div><div>-XX:+G1YoungGenSize=512m (q轻代大?12M) </div><div>G1也用幸存空_可能是非q箋的区域)Q它们的大小可以使用一个常见的参数指定Q如Q?/div><div></div><div>-XX:SurvivorRatio=6 </div><div>最后,Zq行G1充分发挥其潜力,试讄以下两个默认被禁用了的参敎ͼ因ؓ它们可能会暴露一个罕见的竞争状态:</div><div></div><div>-XX:+G1ParallelRSetUpdatingEnabled  </div><div> </div><div>-XX:+G1ParallelRSetScanningEnabled  </div><div>注意当设|了-XX:+PrintGCDetails后,G1比v其它HotSpot GC要啰嗦得多,因ؓ它会打印每个GCU程的计时和其它有助于进行故障排除的信息Q如果你想GC日志更简单,请?verbosegc参数?/div><div></div><div>Java 7 G1最新进?/div><div></div><div>G1开发现在主要集中在遗留的可靠性问题和改善性能Q同时也在逐步U除下面的限Ӟ</div><div></div><div>◆G1不能完全支持JVM工具接口QJVM TIQ或Java理扩展QJMXQ,因此关于G1的监视和理工具很可能不能正常工作;</div><div></div><div>◆G1不支持增量永久性代回收Q如果一个应用程序生了许多c{储,需要永久性代回收Q这在完整GC期间是可以实现的Q?/div><div></div><div>◆从GC暂停旉来说QG1有时表现比CMS好有时比CMS差?/div><div></div><div>原文QJava 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年MQYoung GenerationQ、年老代QOld GenerationQ和怹代(Permanent GenerationQ。年M和年老代是存储动态生的对象。永久带主要是存储的是java的类信息Q包括解析得到的Ҏ、属性、字D늭{。永久带基本不参与垃圑֛收。我们这里讨论的垃圾回收主要是针对年M和年老代。具体如下图?br />


q轻代又分成3个部分,一个eden区和两个相同的survior区。刚开始创建的对象都是攄在eden区的。分成这?个部分,主要是ؓ了生命周期短的对象尽量留在年d。当eden区申请不到空间的时候,q行minorGCQ把存活的对象拷贝到survior。年老代主要存放生命周期比较长的对象Q比如缓存对象。具体jvm内存回收q程描述如下Q可以结合上图)Q?/p>

1、对象在Eden区完成内存分?br />2、当Eden区满了,再创建对象,会因为申请不到空_触发minorGCQ进行young(eden+1survivor)区的垃圾回收
3、minorGCӞEden不能被回收的对象被放入到I的survivorQEden肯定会被清空Q,另一个survivor里不能被GC回收的对象也会被攑օq个survivorQ始l保证一个survivor是空?br />4、当做第3步的时候,如果发现survivor满了Q则q些对象被copy到old区,或者survivorq没有满Q但是有些对象已l够OldQ也被放入Old?nbsp;XX:MaxTenuringThreshold
5、当Old放满的之后,q行fullGC

在知道垃圑֛收机制以后,大家可以在对jvm中堆的各个参数进行优化设|,来提高性能?/p>









abin 2014-12-24 23:41 发表评论
]]>
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的时候,会有一步是符号引用解析ؓ直接引用的过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';">对于指向“cd”【Class对象】、类变量、类Ҏ的直接引用可能是<span style="background-color: #ffccff;">指向Ҏ区的本地指针</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;">实例Ҏ的直接引用可能是Ҏ表的偏移?/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量和父cM的方法表的偏U量是一致的。比如说父类中有一个say()Ҏ的偏U量?Q那么子cMsayҎ的偏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;">搜烦对象的类的方法表</span>才能扑ֈ一个合适的Ҏ。这是因?span style="background-color: #ffccff;">实现同一个接口的q些cMQ不一定所有的接口中的Ҏ在类ҎZ的偏U量都是一L</span>。他们有可能会不一栗这L话可能就要搜索方法表才能认要调用的Ҏ在哪里?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei';">而通过“cd?#8221;来调用一个方法的时候,直接通过偏移量就可以扑ֈ要调用的Ҏ的位|了。【因为子cM的方法的偏移量跟父类中的偏移量是一致的?/span></p><p style="color: #362e2b; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 'Microsoft YaHei'; background-color: #339999;">所以,通过接口引用调用Ҏ会比cd用慢一些?/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出了被引用的内容的名字q且可能会包含一些其他关于这个被引用的信息——q些信息必须以唯一的识别一个类、字Dc方法。这P对于其他cȝW号引用必须l出cȝ全名。对于其他类的字D,必须l出cd、字D名以及字段描述W。对于其他类的方法的引用必须l出cd、方法名以及Ҏ的描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;">ȝQJVM对于直接引用和符号引用的处理是有区别的,可以看到W号引用ӞJVM用StringBuilder来完成字W串?nbsp; dQ而直接引用时则直接用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;">反编译后的:</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;">反编译后的:</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
引发此问题的原因有两个:

1.U程数超q了操作pȝ的限制?br />
* 使用top命o查看pȝ资源Q如果发现剩余内存很多,而又出现此异常,则基本可以肯定是׃操作pȝU程数限制引L?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 />
正确的修Ҏ式是修改/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认到是内存不Q则可以通过java启动参数 -Xss修改每个U程栈大。减此参数Q可以提高最大线E数。当Ӟ要保证你的线E用的内存不会过q个数?br />
当然Q如果不是因为系l别的问题Q那q优化E序了,查有没有泄露的内存,有没有业务逻辑存在大量q发{等?br />

abin 2014-12-15 12:08 发表评论
]]>
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解释一下:

  注意Q?span style="color: #ff0000;">两个survivor是交替用的Q在L一个时刻,必定有一个survivor为空Q一个survivor中存攄对象Q连l存放,无碎片)。回收过E如下:

  S1、GCQ将eden中的live对象攑օ当前不ؓI的survivor中,eden中的非live对象回收。如果survivor满了Q下ơ回收执行S2Q如果survivor未满Q下ơ回收仍然以S1的方式回Ӟ

  S2、GCQ将eden和存攄对象的survivor中的live对象攑օ当前为空的survivor中,非live对象回收?/p>

  可以看到Q上q的新生代回收机制保证了一个survivor为空Q另一个非Isurvivor中无片?/p>

  在执行一定次数的minor GC后,会通过Full GC新生代的survivor中的对象Ud老年代?/p>


  对于理解GC的整个机Ӟ推荐一非常好的文?/span>Q?a target="_blank" style="color: #ca0000; text-decoration: none;">http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/



abin 2014-12-09 14:16 发表评论
]]>
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 spaceQ?2个survivor<br />q青代用来存放新q创建的对象Q尺寔R堆大的增大和减而相应的变化Q默认值是保持为堆大小?/15Q可以通过-Xmn参数讄q青代ؓ固定大小Q也可以通过-XX:NewRatio来设|年青代与年老代的大比例,q青代的特点是对象更新速度快,在短旉内生大量的“M对象”?br />q轻代的特点是生大量的M对象,q且要是产生q箋可用的空? 所以用复制清除算法和q行攉器进行垃圑֛?     对年M的垃圑֛收称作初U回?nbsp;(minor gc)<br /><br />初回收年M分ؓ三个区域,  一个新生代 , 2个大相同的复活?  应用E序只能使用一个新生代和一个复zM, 当发生初U垃圑֛收的时?gc挂vE序, 然后新生代和复zM中的存活对象复制到另外一个非zd的复zM?然后一ơ性清除新生代和复zM,原来的非复zM标记成ؓzd复活?    在指定ơ数回收后仍然存在的对象Ud到年老代? 初回收?得到一个空的可用的新生?<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中类加蝲序及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的一个脚本,发现一个JavacM乎没有在classpath中,好像也可一直运行了。很疑惑Q问了对应的开发同学,然后自己好好看了下它的代码,才知道了原理?/div><div>命o是:$JAVA_HOME/bin/java $JAVA_OPTS com.alibaba.standalone.AppStartor com.alibaba.intl.standalone.databrusher.Startor "$main_class" "$signal_file" "$recivers"</div><div>原理是:JavaҎclasspath扑ֈQcom.alibaba.standalone.AppStartorq个classQ运行这个classQ会启动一个classloader来加载com.alibaba.intl.standalone.databrusher.StartorQ在里面会指定到WORLDS-INF目录下加载类Q,然后com.alibaba.intl.standalone.databrusher.Startor会启动对应的"$main_class".</div><div>然后Q花了挺多时间好好看了一下Java的classloaderQ了解一下其中的原理和看了下代码。下面也单ȝ一下吧?/div><div>java虚拟机是由sun.misc.Launcher来初始化?也就是java(或java.exe)q个E序来做?虚拟机按以下序搜烦q装载所有需要的c?</div><div>  1,引导c?l成javaq_的类,包含rt.jar和i18n.jar{基jar包中的类.</div><div>  2,扩展c?使用java扩展机制的类,都是位于扩展目录($JAVA_HOME/jre/lib/ext)中的.jar档案?</div><div>  3,用户c?开发者定义的cL者没有用java扩展机制的第三方产品.你必d命o行中使用-classpath选项或者用CLASSPATH环境变量来确定这些类的位Q或者自己写ClassLoader加蝲?/div><div></div><div>Java的class loader的大致情况如下图所C:</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会先做一些初始化的动作。一旦初始化动作完成之后Q就?产生W一个类别加载器Q即所谓的Bootstrap LoaderQBootstrap Loader 是由C++ 所撰写而成Q这个Bootstrap Loader所做的初始工作中,除了也做一些基本的初始化动作之外,最重要的就是加载定义在sun.misc 命名I间底下的Launcher.java 之中的ExtClassLoader( 因ؓ是inner class Q所以编译之后会变成Launcher$ExtClassLoader.class) Qƈ讑֮其Parent 为nullQ代表其父加载器为Bootstrap Loader 。然后Bootstrap Loader ,再要求加载定义于sun.misc 命名I间底下的Launcher.java 之中的AppClassLoader( 因ؓ是inner classQ所以编译之后会变成Launcher$AppClassLoader.class) Qƈ讑֮其Parent Z前生的ExtClassLoader 实例?/div><div>a. Bootstrap ClassLoader/启动cd载器</div><div>主要负责java_home/jre/lib目录下的核心 api ?-Xbootclasspath 选项指定的jar包装入工?</div><div>b. Extension ClassLoader/扩展cd载器</div><div>主要负责java_home/jre/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工?/div><div>c. System ClassLoader/pȝcd载器</div><div>主要负责java -classpath/-Djava.class.path?CLASSPATH变量所指的目录下的cMjar包装入工?(q里需要说明的是,如果$CLASSPATH为空Qjdk会默认将被运行的Javacȝ当前路径作ؓ一个默认的$CLASSPATHQ一但设|了$CLASSPATH变量Q则会到$CLASSPATH对应的\径下d扄应的c,找不到就会报错。这个结论,我已l经q测试,q且看了下类加蝲器中源代码)</div><div>d. User Custom ClassLoader/用户自定义类加蝲c?java.lang.ClassLoader的子c?在程序运行期? 通过java.lang.ClassLoader的子cd态加载class文g, 体现java动态实时类装入Ҏ?</div><div></div><div>Z有更多的了解Q写了个单的JavaE序对前面三Uclassloader能加载类的\径及其parentc进行了试。代码如下:<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及其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先打印一个\径,再打印出其parentQ然后再打印出类加蝲路径中的所有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仅通过一天的了解Q记录ؓ上面那么多吧。更多详l信息,可以参考如下资料:</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

abin 2013-07-26 10:48 发表评论
]]>
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内存模型及垃圾收集算?/p>

 1.ҎJava虚拟范,JVM内存划分ؓQ?/p>

  • NewQ年MQ?/li>
  • TenuredQ年老代Q?/li>
  • 怹代(PermQ?/li>

  其中New和Tenured属于堆内存,堆内存会从JVM启动参数Q?Xmx:3GQ指定的内存中分配,Perm不属于堆内存Q有虚拟机直接分配,但可以通过-XX:PermSize -XX:MaxPermSize {参数调整其大小?/p>

  • q轻代(NewQ:q轻代用来存放JVM刚分配的Java对象
  • q老代QTenured)Q年M中经q垃圑֛收没有回收掉的对象将被Copy到年老代
  • 怹代(PermQ:怹代存放Class、Method元信息,其大跟目的规模、类、方法的量有养I一般设|ؓ128Mp够,讄原则是预?0%的空间?/li>

New又分为几个部分:

  • EdenQEden用来存放JVM刚分配的对象
  • Survivor1
  • Survivro2Q两个SurvivorI间一样大Q当Eden中的对象l过垃圾回收没有被回收掉Ӟ会在两个Survivor之间来回CopyQ当满某个条gQ比如Copyơ数Q就会被Copy到Tenured。显ӞSurvivor只是增加了对象在q轻代中的逗留旉Q增加了被垃圑֛收的可能性?/li>

 2.垃圾回收法

  垃圾回收法可以分ؓ三类Q都Z标记-清除Q复Ӟ法Q?/p>

  • Serial法Q单U程Q?/li>
  • q行法
  • q发法

  JVM会根据机器的g配置Ҏ个内存代选择适合的回收算法,比如Q如果机器多?个核Q会对年M选择q行法Q关于选择l节请参考JVM调优文档?/p>

  E微解释下的是,q行法是用多线E进行垃圑֛Ӟ回收期间会暂停程序的执行Q而ƈ发算法,也是多线E回Ӟ但期间不停止应用执行。所以,q发法适用于交互性高的一些程序。经q观察,q发法会减年M的大,其实是使用了一个大的年老代Q这反过来跟q行法相比吞吐量相对较低?/p>

  q有一个问题是Q垃圑֛收动作何时执行?

  • 当年M内存满时Q会引发一ơ普通GCQ该GC仅回收年M。需要强调的Ӟq轻代满是指Eden代满QSurvivor满不会引发GC
  • 当年老代满时会引发Full GCQFull GC会同时回收q轻代、年老代
  • 当永久代满时也会引发Full GCQ会DClass、Method元信息的卸蝲

  另一个问题是Q何时会抛出OutOfMemoryExceptionQƈ不是内存被耗空的时候才抛出

  • JVM98%的时间都p在内存回?/li>
  • 每次回收的内存小?%

  满q两个条件将触发OutOfMemoryExceptionQ这会留给pȝ一个微的间隙以做一些Down之前的操作,比如手动打印Heap Dump?/p>

二、内存泄漏及解决Ҏ

 1.pȝ崩溃前的一些现象:

    • 每次垃圾回收的时间越来越长,׃前的10ms廉?0ms左右QFullGC的时间也有之前的0.5s廉??s
    • FullGC的次数越来越多,最频繁旉不到1分钟p行一ơFullGC
    • q老代的内存越来越大ƈ且每ơFullGC后年老代没有内存被释?/li>

       之后pȝ会无法响应新的请求,逐渐到达OutOfMemoryError的界倹{?/p>

       2.生成堆的dump文g

       通过JMX的MBean生成当前的Heap信息Q大ؓ一?GQ整个堆的大)的hprof文gQ如果没有启动JMX可以通过Java的jmap命o来生成该文g?/p>

       3.分析dump文g

       下面要考虑的是如何打开q个3G的堆信息文gQ显然一般的Windowpȝ没有q么大的内存Q必d助高配|的Linux。当然我们可以借助X-Window把Linux上的囑Ş导入到Window。我们考虑用下面几U工h开该文Ӟ

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

       使用q些工具时ؓ了确保加载速度Q徏议设|最大内存ؓ6G。用后发现Q这些工具都无法直观地观察到内存泄漏QVisual VM虽能观察到对象大,但看不到调用堆栈QHeapAnalyzer虽然能看到调用堆栈,却无法正打开一?G的文件。因此,我们又选用了Eclipse专门的静态内存分析工PMat?/p>

       4.分析内存泄漏

       通过Mat我们能清楚地看到Q哪些对象被怀疑ؓ内存泄漏Q哪些对象占的空间最大及对象的调用关pR针Ҏ案,在ThreadLocal中有很多的JbpmContext实例Q经q调查是JBPM的Context没有关闭所致?/p>

       另,通过Mat或JMX我们q可以分析线E状态,可以观察到线E被d在哪个对象上Q从而判断系l的瓉?/p>

       5.回归问题

         QQ?span style="color: #0000ff">Z么崩溃前垃圾回收的时间越来越长?

         A:Ҏ内存模型和垃圑֛收算法,垃圾回收分两部分Q内存标记、清除(复制Q,标记部分只要内存大小固定旉是不变的Q变的是复制部分Q因为每ơ垃圑֛攉有一些回收不掉的内存Q所以增加了复制量,D旉廉。所以,垃圾回收的时间也可以作ؓ判断内存泄漏的依?/span>

         QQ?span style="color: #0000ff">Z么Full GC的次数越来越多?

         AQ?span style="color: #ff6600">因此内存的积累,逐渐耗尽了年老代的内存,D新对象分配没有更多的I间Q从而导致频J的垃圾回收

         Q:Z么年老代占用的内存越来越大?

         A:因ؓq轻代的内存无法被回Ӟ来多地被Copy到年老代

      三、性能调优

       除了上述内存泄漏外,我们q发现CPU长期不3%Q系l吞吐量不够Q针?core×16G?4bit的Linux服务器来_是严重的资源费?/p>

       在CPU负蝲不的同Ӟ偶尔会有用户反映h的时间过长,我们意识到必dE序及JVMq行调优。从以下几个斚wq行Q?/p>

      • U程池:解决用户响应旉长的问题
      • q接?/li>
      • JVM启动参数Q调整各代的内存比例和垃圑֛收算法,提高吞吐?/li>
      • E序法Q改q程序逻辑法提高性能

        1.JavaU程池(java.util.concurrent.ThreadPoolExecutorQ?/p>

          大多数JVM6上的应用采用的线E池都是JDK自带的线E池Q之所以把成熟的JavaU程池进行罗嗦说明,是因U程池的行ؓ与我们想象的有点出入。JavaU程池有几个重要的配|参敎ͼ

      • corePoolSizeQ核心线E数Q最新线E数Q?/li>
      • maximumPoolSizeQ最大线E数Q超q这个数量的d会被拒绝Q用户可以通过RejectedExecutionHandler接口自定义处理方?/li>
      • keepAliveTimeQ线E保持活动的旉
      • workQueueQ工作队列,存放执行的Q?/li>

          JavaU程池需要传入一个Queue参数QworkQueueQ用来存放执行的dQ而对Queue的不同选择Q线E池有完全不同的行ؓQ?/p>

          其实我们的要求很单,希望U程池能跟连接池一P能设|最线E数、最大线E数Q当最数<d<最大数Ӟ应该分配新的U程处理Q当d>最大数Ӟ应该{待有空闲线E再处理该Q务?/p>

          但线E池的设计思\是,d应该攑ֈQueue中,当Queue放不下时再考虑用新U程处理Q如果Queue满且无法z新线E,拒l该d。设计导?#8220;先放{执?#8221;?#8220;放不下再执行”?#8220;拒绝不等?#8221;。所以,Ҏ不同的Queue参数Q要提高吞吐量不能一呛_增大maximumPoolSize?/p>

          当然Q要辑ֈ我们的目标,必须对线E池q行一定的装Q幸q的是ThreadPoolExecutor中留了够的自定义接口以帮助我们辑ֈ目标。我们封装的方式是:

      • 以SynchronousQueue作ؓ参数QmaximumPoolSize发挥作用Q以防止U程被无限制的分配,同时可以通过提高maximumPoolSize来提高系l吞吐量
      • 自定义一个RejectedExecutionHandlerQ当U程数超qmaximumPoolSize时进行处理,处理方式为隔一D|间检查线E池是否可以执行新TaskQ如果可以把拒绝的Task重新攑օ到线E池Q检查的旉依赖keepAliveTime的大?/li>

        2.q接池(org.apache.commons.dbcp.BasicDataSourceQ?/p>

          在用org.apache.commons.dbcp.BasicDataSource的时候,因ؓ之前采用了默认配|,所以当讉K量大Ӟ通过JMX观察到很多TomcatU程都阻塞在BasicDataSource使用的Apache ObjectPool的锁上,直接原因当时是因为BasicDataSourceq接池的最大连接数讄的太,默认的BasicDataSource配置Q仅使用8个最大连接?/p>

          我还观察C个问题,当较长的旉不访问系l,比如2天,DB上的Mysql会断掉所以的q接Q导致连接池中缓存的q接不能用。ؓ了解册些问题,我们充分研究了BasicDataSourceQ发C一些优化的点:

      • Mysql默认支持100个链接,所以每个连接池的配|要Ҏ集群中的机器数进行,如有2台服务器Q可每个讄?0
      • initialSizeQ参数是一直打开的连接数
      • minEvictableIdleTimeMillisQ该参数讄每个q接的空闲时_过q个旉q接被关闭
      • timeBetweenEvictionRunsMillisQ后台线E的q行周期Q用来检过期连?/li>
      • maxActiveQ最大能分配的连接数
      • maxIdleQ最大空闲数Q当q接使用完毕后发现连接数大于maxIdleQ连接将被直接关闭。只有initialSize < x < maxIdle的连接将被定期检是否超期。这个参C要用来在峰D问时提高吞吐量?/li>
      • initialSize是如何保持的Q经q研I代码发玎ͼBasicDataSource会关闭所有超期的q接Q然后再打开initialSize数量的连接,q个Ҏ与minEvictableIdleTimeMillis、timeBetweenEvictionRunsMillis一起保证了所有超期的initialSizeq接都会被重新连接,从而避免了Mysql长时间无动作会断掉连接的问题?/li>

        3.JVM参数

          在JVM启动参数中,可以讄跟内存、垃圑֛收相关的一些参数设|,默认情况不做M讄JVM会工作的很好Q但对一些配|很好的Server和具体的应用必须仔细调优才能获得最x能。通过讄我们希望辑ֈ一些目标:

      • GC的时间够的?/li>
      • GC的次数够的?/li>
      • 发生Full GC的周期够的?/li>

        前两个目前是相悖的,要想GC旉必要一个更的堆,要保证GCơ数_,必须保证一个更大的堆,我们只能取其q?/p>

         Q?Q针对JVM堆的讄一般,可以通过-Xms -Xmx限定其最、最大|Z防止垃圾攉器在最、最大之间收~堆而生额外的旉Q我们通常把最大、最设|ؓ相同的?br />   Q?Q年M和年老代根据默认的比例Q?Q?Q分配堆内存Q可以通过调整二者之间的比率NewRadio来调整二者之间的大小Q也可以针对回收代,比如q轻代,通过 -XX:newSize -XX:MaxNewSize来设|其l对大小。同PZ防止q轻代的堆收~,我们通常会把-XX:newSize -XX:MaxNewSize讄为同样大?/p>

         Q?Q年M和年老代讄多大才算合理Q这个我问题毫无疑问是没有答案的Q否则也׃会有调优。我们观察一下二者大变化有哪些影响

      • 更大的年M必然D更小的年老代Q大的年M会g长普通GC的周期,但会增加每次GC的时_的q老代会导致更频繁的Full GC
      • 更小的年M必然D更大q老代Q小的年M会导致普通GC很频J,但每ơ的GC旉会更短;大的q老代会减Full GC的频?/li>
      • 如何选择应该依赖应用E序对象生命周期的分布情况:如果应用存在大量的时对象,应该选择更大的年MQ如果存在相对较多的持久对象Q年老代应该适当增大。但很多应用都没有这h昄Ҏ,在抉择时应该Ҏ以下两点Q(AQ本着Full GC量的原则Q让q老代量~存常用对象QJVM的默认比?Q?也是q个道理 QBQ通过观察应用一D|_看其他在峰值时q老代会占多少内存Q在不媄响Full GC的前提下Q根据实际情况加大年MQ比如可以把比例控制?Q?。但应该l年老代臛_预留1/3的增长空?/li>

        Q?Q在配置较好的机器上Q比如多核、大内存Q,可以为年老代选择q行攉法Q?-XX:+UseParallelOldGC Q默认ؓSerial攉

        Q?Q线E堆栈的讄Q每个线E默认会开?M的堆栈,用于存放栈、调用参数、局部变量等Q对大多数应用而言q个默认值太了,一?56Kp用。理ZQ在内存不变的情况下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一下一个时间的Java参数配置Q(服务器:Linux 64BitQ?Core×16GQ?/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左右QFull GC基本不发生,或隔很长很长的时间才发生一?/p>

      通过分析dump文g可以发现Q每?时都会发生一ơFull GCQ经q多Ҏ证,只要在JVM中开启了JMX服务QJMX会1时执行一ơFull GC以清除引用,关于q点请参考附件文档?/span>

       4.E序法调优Q本ơ不作ؓ重点

      参考资料:

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



      abin 2013-05-31 15:49 发表评论
      ]]>
      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堆,分配对象实例所在空_是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种复制攉法。由于有一个假设:在一ơ新生代的GC(Minor GC)后大部分的对象占用的内存都会被回Ӟ因此留存的放|GC后仍然活的对象的I间比较小了。这个留存的I间是Survivor spaceQFrom Survivor或To Survivor。这两个SurvivorI间是一样大的。例如,新生代大是10M(Xmn10M)Q那么缺省情况下(-XX:SurvivorRatio=8)QEden Space ?MQFrom和To都是1M?/div>
      在new一个对象时Q先在Eden Space上分配,如果Eden SpaceI间不够p做一ơMinor GC。Minor GC后,要把Eden和From中仍然活着的对象们复制到ToI间中去。如果ToI间不能容纳Minor GC后活着的某个对象,那么该对象就被promote到老年代空间。从EdenI间被复制到ToI间的对象就有了age=1。此age=1的对象如果在下一ơ的Minor GC后仍然存z,它还会被复制到另一个SurvivorI间(如果认ؓFrom和To是固定的Q就是又从To回到了FromI间)Q而它的age=2。如此反复,如果age大于某个阈?-XX:MaxTenuringThreshold=n)Q那个该对象׃可以promote到老年代了?/div>
      如果SurvivorI间中相同age(例如Qage=5)对象的d大于{于SurvivorI间的一半,那么age>=5的对象在下一ơMinor GC后就可以直接promote到老年代,而不用等到age增长到阈倹{?/div>
      在做Minor GCӞ只对新生代做回收Q不会回收老年代。即使老年代的对象无h索引也将仍然存活Q直C一ơFull GC?/div>

      abin 2013-05-28 14:31 发表评论
      ]]>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-btq是64-bitQ限Ӟpȝ的可用虚拟内存限Ӟpȝ的可用物理内存限制?2位系l下Q一般限制在1.5G~2GQ?4为操作系l对内存无限制。我在Windows Server 2003 pȝQ?.5G物理内存QJDK5.0下测试,最大可讄?478m?br />典型讄Q?/strong>
        • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
          -Xmx3550mQ设|JVM最大可用内存ؓ3550M?br />-Xms3550mQ设|JVM促内存?550m。此值可以设|与-Xmx相同Q以避免每次垃圾回收完成后JVM重新分配内存?br />-Xmn2gQ设|年M大小?G?strong>整个堆大?q轻代大?+ q老代大小 + 持久代大?/strong>。持久代一般固定大ؓ64mQ所以增大年M后,会减小q老代大小。此值对pȝ性能影响较大QSun官方推荐配置为整个堆?/8?br />-Xss128kQ设|每个线E的堆栈大小。JDK5.0以后每个U程堆栈大小?MQ以前每个线E堆栈大ؓ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区)与年老代的比|除去持久代)。设|ؓ4Q则q轻代与q老代所占比gؓ1Q?Q年M占整个堆栈的1/5
          -XX:SurvivorRatio=4Q设|年M中EdenZSurvivor区的大小比倹{设|ؓ4Q则两个SurvivorZ一个Eden区的比gؓ2:4Q一个Survivor区占整个q轻代的1/6
          -XX:MaxPermSize=16m:讄持久代大ؓ16m?br />-XX:MaxTenuringThreshold=0Q设|垃圾最大年龄?strong>如果讄?的话Q则q轻代对象不l过Survivor区,直接q入q老代
          。对于年老代比较多的应用Q可以提高效率?strong>如果此D|ؓ一个较大|则年M对象会在Survivor行多ơ复Ӟq样可以增加对象再年M的存zL?/strong>Q增加在q轻代即被回收的概论?/li>
      2. 回收器选择
        JVMl了三种选择Q?strong>串行攉器、ƈ行收集器、ƈ发收集器
        Q但是串行收集器只适用于小数据量的情况Q所以这里的选择主要针对q行攉器和q发攉器。默认情况下QJDK5.0以前都是使用串行攉器,如果想用其他收集器需要在启动时加入相应参数。JDK5.0以后QJVM会根据当?a >pȝ配置q行判断?
        1. 吞吐量优?/strong>的ƈ行收集器
          如上文所qͼq行攉器主要以到达一定的吞吐量ؓ目标Q适用于科学技术和后台处理{?br />典型配置Q?
          • java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
            -XX:+UseParallelGCQ选择垃圾攉器ؓq行攉器?strong>此配|仅对年M有效。即上述配置下,q轻代用ƈ发收集,而年老代仍旧使用串行攉?br />
            -XX:ParallelGCThreads=20Q配|ƈ行收集器的线E数Q即Q同时多个U程一赯行垃圑֛收。此值最好配|与处理器数目相{?
          • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
            -XX:+UseParallelOldGCQ配|年老代垃圾攉方式为ƈ行收集。JDK6.0支持对年老代q行攉?
          • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
            -XX:MaxGCPauseMillis=100:讄每次q轻代垃圑֛收的最长时_如果无法满此时_JVM会自动调整年M大小Q以满此倹{?
          • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100-XX:+UseAdaptiveSizePolicy
            -XX:+UseAdaptiveSizePolicy
            Q设|此选项后,q行攉器会自动选择q轻代区大小和相应的Survivor区比例,以达到目标系l规定的最低相应时间或者收集频率等Q此值徏议用ƈ行收集器Ӟ一直打开?/li>
      3. 响应旉优先的ƈ发收集器
        如上文所qͼq发攉器主要是保证pȝ的响应时_减少垃圾攉时的停顿旉。适用于应用服务器、电信领域等?br />典型配置Q?
        • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
          -XX:+UseConcMarkSweepGCQ设|年老代为ƈ发收集。测试中配置q个以后Q?XX:NewRatio=4的配|失效了Q原因不明。所以,此时q轻代大最好用-Xmn讄?br />-XX:+UseParNewGC:讄q轻代ؓq行攉。可与CMS攉同时使用。JDK5.0以上QJVM会根据系l配|自行设|,所以无需再设|此倹{?
        • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
          -XX:CMSFullGCsBeforeCompactionQ由于ƈ发收集器不对内存I间q行压羃、整理,所以运行一D|间以后会产生“片”Q得运行效率降低。此D|运行多次GC以后对内存空间进行压~、整理?br />-XX:+UseCMSCompactAtFullCollectionQ打开对年老代的压~。可能会影响性能Q但是可以消除碎?/li>
    1. 辅助信息
      JVM提供了大量命令行参数Q打C息,供调试用。主要有以下一些:
      • -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:+PrintGCQPrintGCTimeStamps可与上面两个混合使用
        输出形式Q?strong>11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
      • -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,E序未中断的执行旉。可与上面؜合?br />输出形式Q?strong>Application time: 0.5291524 seconds
      • -XX:+PrintGCApplicationStoppedTimeQ打印垃圑֛收期间程序暂停的旉。可与上面؜合?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ؓ1Q?Q年M占整个年Mq老代和的1/4
        • -XX:SurvivorRatio=n:q轻代中EdenZ两个Survivor区的比倹{注意Survivor区有两个。如Q?Q表CEdenQSurvivor=3Q?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:讄垃圾回收旉占程序运行时间的癑ֈ比。公式ؓ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发攉器,所以其大小需要小心设|,一般要考虑q发会话?/strong>?strong>会话持箋旉{一些参数。如果堆讄了Q可以会造成内存片、高回收频率以及应用暂停而用传l的标记清除方式Q如果堆大了Q则需要较长的攉旉。最优化的方案,一般需要参考以下数据获得:
          • q发垃圾攉信息
          • 持久代ƈ发收集次?
          • 传统GC信息
          • 花在q轻代和q老代回收上的旉比例
      3. 减少q轻代和q老代p的时_一般会提高应用的效?/li>
      4. 吞吐量优先的应用Q一般吞吐量优先的应用都有一个很大的q轻代和一个较的q老代。原因是Q这样可以尽可能回收掉大部分短期对象Q减中期的对象Q而年老代存N期存zd象?/li>
      5. 较小堆引L片问题
        因ؓq老代的ƈ发收集器使用标记、清除算法,所以不会对堆进行压~。当攉器回收时Q他会把盔R的空间进行合qӞq样可以分配l较大的对象。但是,当堆I间较小Ӟq行一D|间以后,׃出现“片”Q如果ƈ发收集器找不到够的I间Q那么ƈ发收集器会停止Q然后用传l的标记、清除方式进行回收。如果出?#8220;片”Q可能需要进行如下配|:
        • -XX:+UseCMSCompactAtFullCollectionQ用ƈ发收集器Ӟ开启对q老代的压~?
        • -XX:CMSFullGCsBeforeCompaction=0Q上面配|开启的情况下,q里讄多少ơFull GC后,对年老代q行压羃
      6. jvm的内存限?/li>

              windows2003?612M



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

      abin 2012-11-14 13:48 发表评论
      ]]>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 -Xmx3550mQ设|JVM最大可用内存ؓ3550M? -Xms3550mQ设|JVM促内存?550m。此值可以设|与-Xmx相同Q以避免每次垃圾回收完成后JVM重新分配内存? -Xmn2gQ设|年M大小?G。整个堆大小=q轻代大?+ q老代大小 + 持久代大。持久代一般固定大ؓ64mQ所以增大年M后,会减小q老代大小。此值对pȝ性能影响较大QSun官方推荐配置为整个堆?/8? -Xss128kQ设|每个线E的堆栈大小。JDK5.0以后每个U程堆栈大小?MQ以前每个线E堆栈大ؓ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区)与年老代的比|除去持久代)。设|ؓ4Q则q轻代与q老代所占比gؓ1Q?Q年M占整个堆栈的1/5 -XX:SurvivorRatio=4Q设|年M中EdenZSurvivor区的大小比倹{设|ؓ4Q则两个SurvivorZ一个Eden区的比gؓ2:4Q一个Survivor区占整个q轻代的1/6 -XX:MaxPermSize=16m:讄持久代大ؓ16m? -XX:MaxTenuringThreshold=0Q设|垃圾最大年龄。如果设|ؓ0的话Q则q轻代对象不l过Survivor区,直接q入q老代。对于年老代比较多的应用Q可以提高效率。如果将此D|ؓ一个较大|则年M对象会在Survivor行多ơ复Ӟq样可以增加对象再年M的存zL_增加在年M卌回收的概论?/pre>

      abin 2012-11-14 13:40 发表评论
      ]]>
      利用 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阅读全文

      abin 2012-11-14 13:01 发表评论
      ]]>
      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序异常QL可以知道在什么时候或是在什么操作步骤上出现了异常,而且Ҏ堆栈信息也很Ҏ定位到程序中是某处出C问题。内存溢Z锁表则不Ӟ一般现象是操作一般时间后pȝ来慢Q直到死机,但ƈ不能明确是在什么操作上出现的,发生的时间点也没有规律,查看日志?span style="background-color: yellow; color: #ee6600" id="Mark">查看数据库也不能定位出问题的代码?/p>

      更严重的是内存溢Z数据库锁表在pȝ开发和单元试阶段q不Ҏ被发玎ͼ当系l正式上U一般时间后Q操作的q发量上来了Q数据也U篏了一些,pȝ容易出现内存溢出或是锁表的现象Q而此时系l又不能随意停机或重启,Z正BUG带来很大的困难?/p>

      本文以笔者开发和支持的多个项目ؓ例,与大家分享在开发过E中遇到的Java内存溢出和数据库锁表的检和处理解决q程?/p>

      2Q内存溢出的分析
      内存溢出是指应用pȝ中存在无法回收的内存或用的内存q多Q最l得程序运行要用到的内存大于虚拟机能提供的最大内存。ؓ了解决Java中内存溢出问题,我们首先必须了解Java是如何管理内存的。Java的内存管理就是对象的分配和释N题。在Java中,内存的分配是q序完成的Q而内存的释放是由垃圾攉?Garbage CollectionQGC)完成的,E序员不需要通过调用GC函数来释攑ֆ存,因ؓ不同的JVM实现者可能用不同的法理GCQ有的是内存使用到达一定程度时QGC才开始工作,也有定时执行的,有的是中断式执行GC。但GC只能回收无用q且不再被其它对象引用的那些对象所占用的空间。Java的内存垃圑֛收机制是从程序的主要q行对象开始检查引用链Q当遍历一遍后发现没有被引用的孤立对象׃为垃圑֛收?/p>

      引v内存溢出的原因有很多U,常见的有以下几种Q?/p>

      l         内存中加载的数据量过于庞大,如一ơ从数据库取多数据;

      l         集合cM有对对象的引用,使用完后未清I,使得JVM不能回收Q?/p>

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

      l         使用的第三方软g中的BUGQ?/p>

      l         启动参数内存D定的q小Q?/p>

      3Q内存溢出的解决
      内存溢出虽然很棘手,但也有相应的解决办法Q可以按照从易到难,一步步的解冟?/p>

      W一步,是修改JVM启动参数Q直接增加内存。这一点看上去g很简单,但很Ҏ被忽略。JVM默认可以使用的内存ؓ64MQTomcat默认可以使用的内存ؓ128MBQ对于稍复杂一点的pȝ׃不够用。在某项目中Q就因ؓ启动参数使用的默认|l常?#8220;OutOfMemory”错误。因此,-XmsQ?Xmx参数一定不要忘记加?/p>

      W二步,查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。在一个项目中Q用两个数据库q接Q其中专用于发送短信的数据库连接用DBCPq接池管理,用户Z短信发出,有意数据库q接用户名改错,使得日志中有许多数据库连接异常的日志Q一D|间后Q就出现“OutOfMemory”错误。经分析Q这是由于DBCPq接池BUG引v的,数据库连接不上后Q没有将q接释放Q最l得DBCP?#8220;OutOfMemory”错误。经q修Ҏ数据库q接参数后,没有再出现内存溢出的错误?/p>

      查看日志对于分析内存溢出是非帔R要的Q通过仔细查看日志Q分析内存溢出前做过哪些操作Q可以大致定位有问题的模块?/p>

      W三步,安排有经验的~程人员对代码进行走查和分析Q找出可能发生内存溢出的位置。重Ҏ查以下几点:

      l         查代码中是否有死循环或递归调用?/p>

      l         查是否有大@环重复生新对象实体?/p>

      l         查对数据库查询中Q是否有一ơ获得全部数据的查询。一般来_如果一ơ取十万条记录到内存Q就可能引v内存溢出。这个问题比较隐蔽,在上U前Q数据库中数据较,不容易出问题Q上U后Q数据库中数据多了,一ơ查询就有可能引起内存溢出。因此对于数据库查询量采用分页的方式查询?/p>

      l         查List、MAP{集合对象是否有使用完后Q未清除的问题。List、MAP{集合对象会始终存有对对象的引用Q得这些对象不能被GC回收?/p>

      W四步,使用内存查看工具动?span style="background-color: yellow; color: #ee6600" id="Mark">查看内存使用情况。某个项目上U后Q每ơ系l启动两天后Q就会出现内存溢出的错误。这U情况一般是代码中出C~慢的内存泄漏,用上面三个步骤解决不了,q就需要用内?span style="background-color: yellow; color: #ee6600" id="Mark">查看工具了?/p>

      内存查看工具有许多,比较有名的有QOptimizeit Profiler、JProbe Profiler、JinSight和Java1.5的Jconsole{。它们的基本工作原理大同异Q都是监JavaE序q行时所有对象的甌、释攄动作Q将内存理的所有信息进行统计、分析、可视化。开发h员可以根据这些信息判断程序是否有内存泄漏问题。一般来_一个正常的pȝ在其启动完成后其内存的占用量是基本稳定的Q而不应该是无限制的增长的。持l地观察pȝq行时用的内存的大,可以看到在内存用监控窗口中是基本规则的锯形的囄Q如果内存的大小持箋地增长,则说明系l存在内存泄漏问题。通过间隔一D|间取一ơ内存快照,然后对内存快照中对象的用与引用{信息进行比对与分析Q可以找出是哪个cȝ对象在泄漏?/p>

      通过以上四个步骤的分析与处理Q基本能处理内存溢出的问题。当Ӟ在这些过E中也需要相当的l验与敏感度Q需要在实际的开发与调试q程中不断积累?/p>

      M上来_产生内存溢出是由于代码写的不好造成的,因此提高代码的质量是最Ҏ的解军_法。有的h认ؓ先把功能实现Q有BUG时再在测试阶D进行修正,q种x是错误的。正如一件品的质量是在生刉的q程中决定的Q而不是质量检时军_的,软g的质量在设计与编码阶D就已经军_了,试只是对Y件质量的一个验证,因ؓ试不可能找Y件中所有的BUG?/p>

       

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

       

      原因有很多种Q比如:

      1.数据量过于庞大;d@?Q静态变量和静态方法过多;递归Q无法确定是否被引用的对象;

      2.虚拟Z回收内存Q内存泄漏)Q?/p>

          说白了就是程序运行要用到的内存大于虚拟机能提供的最大内存就发生内存溢出了?内存溢出的问题要看业务和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 理两种cd的内存,堆和非堆。堆是给开发h员用的上面说的就是,是在 JVM 启动时创建;非堆是留l?JVM 自己用的Q用来存攄的信息的。它和堆不同Q运行期?GC 不会释放I间。如?web app 用了大量的第三方 jar 或者应用有太多?class 文g而恰?MaxPermSize 讄较小Q超Z也会Dq块内存的占用过多造成溢出Q或?tomcat 热部|时侯不会清理前面加载的环境Q只会将 context 更改为新部v的,非堆存的内容׃来多?/p>

      2 ?java.lang.OutOfMemoryError: Java heap space

      W一U情冉|个补充,主要存在问题是出现在这个情况中。其默认I间 ( ?-Xms) 是物理内存的 1/64 Q最大空?(-Xmx) 是物理内存的 1/4 。如果内存剩余不?40 Q, JVM ׃增大堆到 Xmx 讄的|内存剩余过 70 Q, JVM ׃减小堆到 Xms 讄的倹{所以服务器?Xmx ?Xms 讄一般应该设|相同避免每?GC 后都要调整虚拟机堆的大小。假讄理内存无限大Q那?JVM 内存的最大D操作pȝ有关Q一?32 位机?1.5g ?3g 之间Q?64 位的׃会有限制了?/p>

      注意Q如?Xms 过?Xmx |或者堆最大值和非堆最大值的d过了物理内存或者操作系l的最大限刉会引h务器启动不v来?/p>

      垃圾回收 GC 的角?/p>

      JVM 调用 GC 的频度还是很高的Q主要两U情况下q行垃圾回收Q?/p>

      当应用程序线E空Ԍ另一个是 java 内存堆不xQ会不断调用 GC Q若q箋回收都解决不了内存堆不的问题时Q就会报 out of memory 错误。因个异常根据系l运行环境决定,所以无法预期它何时出现?/p>

      Ҏ GC 的机ӞE序的运行会引vpȝq行环境的变化,增加 GC 的触发机会?/p>

      Z避免q些问题Q程序的设计和编写就应避免垃圑֯象的内存占用?GC 的开销。显C?System.GC() 只能 JVM 需要在内存中对垃圾对象q行回收Q但不是必须马上回收Q?/p>

      一个是q不能解军_存资源耗空的局面,另外也会增加 GC 的消耗?/p>

      二?JVM 内存区域l成
      单的?java中的堆和?/p>

      java把内存分两种Q一U是栈内存,另一U是堆内?/p>

      1。在函数中定义的基本cd变量和对象的引用变量都在函数的栈内存中分配;

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

      在函敎ͼ代码块)中定义一个变量时Q?java在栈中个变量分配内存空_当超q变量的作用域后Q?java会自动释放掉变量所分配的内存空_在堆中分配的内存?java虚拟机的自动垃圾回收器来理

      堆的优势是可以动态分配内存大,生存期也不必事先告诉~译器,因ؓ它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢Q?/p>

      栈的优势是存取速度比堆要快Q缺Ҏ存在栈中的数据大与生存期必L定的无灉| 性?/p>

      java 堆分Z个区Q?New ?Old ?Permanent

      GC 有两个线E:

      新创建的对象被分配到 New 区,当该填满时会?GC 辅助U程Ud Old 区,?Old Z填满了会触发 GC ȝE遍历堆内存里的所有对象?Old 区的大小{于 Xmx 减去 -Xmn

      java栈存?/p>

      栈调_参数?+UseDefaultStackSize -Xss256KQ表C每个线E可甌 256k的栈I间

      每个U程都有他自q Stack

      三?JVM如何讄虚拟内存
      提示Q在 JVM中如?98Q的旉是用?GC且可用的 Heap size 不 2Q的时候将抛出此异怿息?/p>

      提示Q?Heap Size 最大不要超q可用物理内存的 80Q,一般的要将 -Xms?-Xmx选项讄为相同,?-Xmn?1/4?-Xmx倹{?/p>

      提示Q?JVM初始分配的内存由 -Xms指定Q默认是物理内存?1/64Q?JVM最大分配的内存?-Xmx指定Q默认是物理内存?1/4?/p>

      默认IZ堆内存小?40%Ӟ JVM׃增大堆直?-Xmx的最大限ӞIZ堆内存大?70%Ӟ JVM会减堆直到 -Xms的最限制。因此服务器一般设|?-Xms?-Xmx相等以避免在每次 GC 后调整堆的大?/p>

      提示Q假讄理内存无限大的话Q?JVM内存的最大D操作pȝ有很大的关系?/p>

      单的说就 32位处理器虽然可控内存I间?4GB,但是具体的操作系l会l一个限Ӟ

      q个限制一般是 2GB-3GBQ一般来?Windowspȝ下ؓ 1.5G-2GQ?Linuxpȝ下ؓ 2G-3GQ, ?64bit以上的处理器׃会有限制?/p>

      提示Q注意:如果 Xms过?Xmx|或者堆最大值和非堆最大值的d过了物理内 存或者操作系l的最大限刉会引h务器启动不v来?/p>

      提示Q设|?NewSize?MaxNewSize相等Q?“new”的大最好不要大?“old”的一半,原因?old区如果不够大会频J的触发 “?” GC Q大大降低了性能

      JVM使用 -XX:PermSize讄非堆内存初始|默认是物理内存的 1/64Q?/p>

      ?XX:MaxPermSize讄最大非堆内存的大小Q默认是物理内存?1/4?/p>

      解决ҎQ手动设|?Heap size

      修改 TOMCAT_HOME/bin/catalina.bat

      ?#8220; echo “Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:

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

      四、性能查工具?/font>
      定位内存泄漏Q?/p>

      JProfiler 工具主要用于查和跟踪pȝQ限?Java 开发的Q的性能?JProfiler 可以通过时时的监控系l的内存使用情况Q随时监视垃圑֛ӞU程q行状况{手D,从而很好的监视 JVM q行情况及其性能?/p>


      1. 应用服务器内存长期不合理占用Q内存经常处于高位占用,很难回收C位;

      2. 应用服务器极ZE_Q几乎每两天重新启动一ơ,有时甚至每天重新启动一ơ;

      3. 应用服务器经常做 Full GC(Garbage Collection)Q而且旉很长Q大U需?30-40U,应用服务器在?Full GC的时候是不响应客L交易h的,非常影响pȝ性能?/p>

      因ؓ开发环境和产品环境会有不同Q导致该问题发生有时会在产品环境中发生, 通常可以使用工具跟踪pȝ的内存用情况,在有些个别情况下或许某个时刻实 是用了大量内存D out of memoryQ这时应l箋跟踪看接下来是否会有下降Q?/p>

      如果一直居高不下这肯定因为程序的原因D内存泄漏?/p>

      五、不健壮代码的特征及解决办法
      1 、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动讄?null Q暗C垃圾收集器来收集该对象Q防止发生内存泄霌Ӏ?/p>

      对于仍然有指针指向的实例Q?jvm ׃会回收该资源 , 因ؓ垃圾回收会将gؓ 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 以后再不被调?, 那它׃被放在内存中{待 Java ?gc d?, E序内过多的出现q样的情况就会报上面的那个错?, 在用字W串时能使用 StringBuffer ׃要用 String, q样可以省不开销Q?  

      3 、尽量少用静态变量,因ؓ静态变量是全局的, GC 不会回收的;

      4 、避免集中创建对象尤其是大对象, JVM 会突焉要大量内存,q时必然会触?GC 优化pȝ内存环境Q显C的声明数组I间Q而且甌数量q极大?/p>

      q是一个案例想定供大家警戒:

      使用jspsmartUpload作文件上?现在q行q程中经常出现java.outofMemoryError的错误,用top命o看看q程使用情况Q发现内存不?MQ花了很长时_发现是jspsmartupload的问题。把jspsmartuploadlg的源码文Ӟclass文gQ反~译成Java文gQ如梦方醒:

      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>

      jspsmartUploadZ末要q样作,有他的原因,ҎRFC1867的http上传标准Q得C个文件流Qƈ不知道文件流的长度。设计者如果想文g的长度,只有操作servletinputstream一ơ才知道Q因ZQ何流都不知道大小。只有知道文仉度了Q才可以限制用户上传文g的长度。ؓ了省去这个麻烦,jspsmartUpload设计者直接在内存中打开文gQ判断长度是否符合标准,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生命周期长的对象拥有生命周期短的对象时Ҏ引发内存泄漏Q例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块q行处理Q然后解决一块释放一块的{略?/p>

      6 、不要在l常调用的方法中创徏对象Q尤其是忌讳在@环中创徏对象。可以适当的?hashtable Q?vector 创徏一l对象容器,然后从容器中d那些对象Q而不用每?new 之后又丢?/p>

      7 、一般都是发生在开启大型文件或跟数据库一ơ拿了太多的数据Q造成 Out Of Memory Error 的状况,q时大概要计算一下数据量的最大值是多少Qƈ且设定所需最及最大的内存I间倹{?/p>



      abin 2012-10-25 23:16 发表评论
      ]]> վ֩ģ壺 ٰ| | ɳ| | | ڰ| | Ρɽ| | | | ԭ| | | | | Ϊ| | ʩ| | Ϫ| Ӻ| ϰ| | | ʯȪ| | | ƽ| | Ƥɽ| | | | | | Ϊ| ٳ| ӳ| | ̳|