堆内存(Heap)

堆是由Java虚拟机(JVM,下文提到的JVM特指Sun hotspot JVM)用来存放Java类、对象和静态成员的内存空间,Java程序中创建的所有对象都在堆中分配空间,堆只用来存储对象,应用程序通过存放在堆栈(Stack)内的引用来访问堆数据,一个JVM进程只能拥有一个堆。JVM通过-Xms和-Xmx参数分别设置堆的初始值和最大值,初始值默认是物理内存的1/64但小于1G,最大值默认是物理内存的1/4但小于1G 。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio来指定百分比。默认空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio来设定百分比。

Java堆使用分代的方式来管理不同类型的Java对象,通常情况下,JVM会将堆分为三个区域(代):年青代(Young),年老代(Old)和永久代(Permanent),针对不同不区域中的不同类型的Java对象JVM采用不同的垃圾回收算法。年青代用来存放新近创建的对象,尺寸随堆大小的增大和减小而相应的变化,默认值是保持为堆大小的1/15,可以通过-Xmn参数设置年青代为固定大小,也可以通过-XX:NewRatio来设置年青代与年老代的大小比例,年青代的特点是对象更新速度快,在短时间内产生大量的“死亡对象”。年老代用来存放存活时间长相对稳定的对象。在年青代中“存活”次数最多的对象会被移动到年老代,通过-XX:MaxTenuringThreshold参数来设置“存活”几次的对象才被移入年老代,年老代的大小由整个堆空间的尺寸减掉年青代和永久代计算得到 。

永久代用来存放类及类的静态成员,这些对象通常来讲很少会被垃圾收集。永久代的初始值和最大值分别通过-XX:PermSize和-XX:MaxPermSize参数来设定。永久代的大小是由JVM独立管理的,并不会随堆的大小变化而变化。当永久代溢出时,JVM会增大永久代的尺寸,但不会超过XX:MaxPermSize设置的最大值,当永久代达到最大值后,继续申请永久代空间将造成系统崩溃(Out of Memery)。年青代在堆内存中是从上向下分配空间的,而永久代则是从下向上分配的,这样作可以最大程度的减少内存碎片的产生。当且只当年老代空间不足时才会触发堆的增长,但不会超过-Xmx设置的上限值。

垃圾回收器(GC)

Java垃圾回收器是一个或多个运行在JVM中低优先级的守护线程,它负责监视JVM堆空间的使用情况,在预定的条件满足时负责回收“死亡对象”,释放可用的内存空间供应用程序使用。死亡对象是指在JVM所有线程堆栈引用中没有任何一个有效指向的对象,死亡对象是无法重新被程序使用的Java对象,在Java中,通过程序无法释放死亡对象的内存空间,JVM使用垃圾回收器来自动的不间断的回收死亡对象。

Java垃圾回收器的三种常用回收算法:

  • 记数器清除(tracing):该算法使用引用计数器来区分存活对象和死亡的对象。堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1,当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。复制清除(replicate):<该算法将堆内存分成两个相同空间,从根(ThreadLocal的对象,静态对象)开始访问每一个关联的活跃对象,将空间A的活跃对象全部复制到空间B,然后一次性回收整个空间A。标记清除(mark-sweep):收集器先从根开始访问所有活跃对象,标记为活跃对象。然后再遍历一次整个内存区域,把所有没有标记活跃的对象进行回收处理。

Java垃圾回收器的三种类型:

  • 串行收集器(Serial):使用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高。但是,也无法使用多处理器的优势,适合单处理器或小尺寸堆(100M左右)环境下使用。使用-XX:+UseSerialGC参数打开该收集器。并行收集器(Parallel):Java5.0新增加的收集器,使用多线程并行的对指定的内存块进行垃圾回收,可以充分的发挥多处理器的优势。使用-XX:+UseParallelGC参数打开该收集器,使用-XX:+UseParallelOldGC参数强制在年老代使用该收集器,使用-XX:ParallelGCThreads参数设置并行收集器使用的线程数 。并发收集器 (ConcMarkSweep):该收集器主要是针对标记清除算法,可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求比较高的中、大规模应用。使用-XX:+UseConcMarkSweepGC打开。Java5.0默认情况下对年青代使用并行收集器(Java1.4使用的是串行收集器),对年老代使用并发收集器,当然可以使用上面提到的参数强制JVM使用其它的收集器。

垃圾回收策略

垃圾回收策略主要是针对年青代和年老代的不同特点分别进行处理的。年青代的特点是产生大量的死亡对象且要求连续的可用空间,所以使用复制清除算法和并行收集器来进行垃圾回收。对年青代的垃圾回收称作叫作初级回收(minor GC)。只有在年青代出现溢出时才会触发初级回收,由于此时年青代已经没有可用空间,所以GC必须挂起应用程序只至回收过程完成。初级回收将年青代分成三个区域,一个新生代(Eden )和两个大小一样的复活代(Survivor),应用程序只能使用新生代和一个复活代(活动复活代),当初级垃圾回收发生时,GC挂起应用程序,将新生代和活动复活代中的存活对象复制到另一个非活动复活代中,然后一次性清除新生代和活动复活代,同时将原来的非复活代标记为活动复活代。初级回收会将存活的对象移动到活动复活代中,将在指定次数回收后仍旧存活的对象移动到年老代中,初级回收的效果是得到一个空的可用的新生代。

年老代的特点是尺寸较大且只存在少量的死亡对象,所以使用标记清除算法和并发收集器来进行垃圾回收。对年老代的垃圾回收又称作次级回收(major GC)。由于年老代比年青代大的多,所以相对于初级回收,次级回收将消耗更多的系统资源和时间。次级回收发生时,GC短暂的挂起应用程序以便标记根对象,然后GC会和应用程序并发执行标记所有的非存活对象,当标记完成时GC再次短暂的挂起应用程序完成清除操作。在清除完成后还会执行一次压缩年老代的操作,以便消除在标记清除过程中产生的内存碎片。由于次级回收大部分时间是和应用程序并发进行的,为了在收集过程中给应用程序留出充足可用内存空间,当年老代的可用空间低于68% 时,JVM就会就会触发次级回收,同时也由于并发执行的原因,次级回收不能100%的回收年老代中所有的死亡对象。

初级回收和次级回收是完全垃圾回收(Full GC)的一部分,完全垃圾回收还会尝试回收永久代(尽管只有很少的概率能从永久代中回收对象,但JVM还是会这样作),通常情况下完全垃圾回收会在以下情况下触发:

  • 次级回收后年老代仍然出现溢出永久代溢出System.gc()被显示调用上一次GC之后Heap的各代分配策略动态变化

完全垃圾回收会消耗相当可观的系统资源,并造成应用程序挂起。一次完全垃圾回收后如果整个堆的可用空间仍然小于指定比例将会造成堆空间的增长,如果堆空间已经达到最大值且仍出现代溢出,则会造成系统崩溃(Out of Memery)。

堆栈内存(Stack)

堆栈(以下简称栈)是由线程管理的一块线性访问的独立于堆的内存空间,一般用来记录程序的执行和存储线程的局部变量,存储在栈中的数据必须在编译阶段确定所占内存的大小。栈空间遵循后进先出的线性访问原则,访问速度要快于堆(Heap)。Java中支持的栈操作只有压栈(Pack)和出栈(Peek)两种,压栈操作将数据存入栈顶,出栈操作将栈顶的数据弹出栈。每一个Java线程对应唯一的一个栈空间,栈空间大小默认值为1M,可以通过设置-Xss参数来增大或缩小为每个线程分配的栈空间,设置过小的栈空间会导致堆栈溢出,设置过大的栈空间会造成最大的线程数减少。

存在于堆空间内的对象一般会在某个或某几个线程对应的栈内找到一个或多个引用,当所有线程对应的栈空间内都找不到引用时,堆内存中的对象就是一个“死亡对象”,死亡对象是Java垃圾回收器负责回收的对象。当同一个堆对象在多个线程中被引用时,通过这些线程访问堆对象可能会出现抢占。为了防止抢占现象的发生,Java提供了线程锁定(Lock)方式来为堆对象加锁,被加锁的堆对象只能被持有该锁的唯一一个线程访问(详见《Java多线程》),栈内存放的数据无法进行锁定。

线程使用的局部变量(方法内变量),无论该变量是堆对象还是基本数据类型,都不会存在抢占现象,当程序运行于多线程模式下时尽量使用局部变量来避免发生抢占。当局部变量引用一个堆对象时,线程结束后该堆对象就变成一个非存活对象。栈空间不受Java垃圾回收器管理,栈的使用完全由程序代码控制,在程序的编译阶段,线程使用的栈空间已经分配完成。当线程结束后,线程对应的栈空间同时被释放。

通过设置-verbose:gc -XX:+PrintGCDetails参数来跟踪系统GC的详细情况,通过设置-XX:+ PrintGCApplicationStoppedTime参数可以显示每次垃圾回收系统挂起的时间。一个好的应用系统会根据年老对象和新生对象的多少来决定堆内存的分配和GC策略的选择,当一个系统存在大量的年老对象时,设置一个小的年青代来减少次级回收的发生频率。反之,当一个系统存在大量的新生对象的时,设置一个大的年青代来减少初级回收的发生频率,有时还需要根据系统加载类的多少来灵活的设置永久代的大小。

JVM如何使用堆内存

当应用程序生成一个新的Java对象,JVM负责在堆内存中为其申请存储空间,通常内存申请过程如下:

  • JVM试图为Java对象在新生代中初始化一块内存区域,当新生代空间足够时,内存申请结束。否则到下一步;JVM试图释放新生代中所有死亡的对象,这将引发初级垃圾回收,初级垃圾回收将新生代中的活跃对象移动到复活代,当复活代空间不足时,复活代的对象会被移动到年老代;当年老代空间不足时,JVM会在年老代进行次级垃圾收集,如果回收后年老代仍然不足以存放新创建的Java对象,则会引发完全垃圾回收,完全垃圾回收会试图回收永久代;如完全垃圾回收后年老代仍然空间不足,JVM会引发堆增长;如堆增长后仍然空间不足,则会重复3和4,直至堆空间增长至最大值;如果当堆的尺寸增长至最大值后仍然无法容纳新的Java对象,则导致JVM无法为新对象创建内存区域,出现“out of memory错误”。

堆内存结构图

当创建一个对象时,JVM首先在堆中为对象分配空间,然后在线程堆栈中压栈一个变量,将变量指向新创建的对象,当将变量置为Null时,该变量不再引用任何对象,先前在堆中创建的对象也因此变为死亡对象。

Person p = new Person();
p = null;
 

灵活的使用虚引用可以避免反复创建对象造成的性能浪费,只有当完全垃圾回收发生时,JVM才会回收虚引用指向的对象。

A a = new A();
a.test();
SoftReference sr = new SoftReference(a);
a = null;
if (sr != null) {   
    a = (A)sr.get();    
    a.test();
else {      
    a = new A();    
    a.test();   
    a = null;   
    sr = new SoftReference(a);
}
 

内存溢出

内存溢出通常发生在JVM无法为新创建的Java对象分配足够的内存空间情况下,针对不同区域的内存分配情况,内存溢出分为以下几种类型。

年老代溢出(java.lang.OutOfMemoryError: Java heap space),这种内存溢出是最常见的情况之一,产生的原因可能是:

  • 堆尺寸设置过小或年青代所占堆内存的比例设置过大(Xms/Xmx, XX:NewRatio);程序所申请内存过大,有的程序会申请几十乃至几百兆内存(如不分页的Grid导出),此时JVM也会因无法申请到资源而出现内存溢出,对此首先要找到相关功能模块,然后交予程序员修改,可以使用JProbe之类的Java调优工具对问题模块进行定位。当Java对象使用完毕后没有及时销毁(内存泄漏),使得JVM认为他还是活跃的对象而不进行回收,这样累计占用了大量内存而无法释放。可以使用JProbe之类的Java调优工具对Dump出来的崩溃的JVM进程进行静态分析,找到泄漏点进行修改。

永久代溢出(java.lang.OutOfMemoryError: Perm Gen):

系统需要加载大量的类或在类中大量使用静态成员时可能会导致永久代溢出,解决方法是加大永久代尺寸(XX:PermSize和XX:MaxPermSize),或修改代码,将静态成员改为普通成员。

堆栈溢出(java.lang.StackOverFlowException):

当程序使用大的递归或循环算法时可能会造成堆栈溢出,比如由于程序设计不当出现死循环或次数超过几千次的递归,解决方法是修改代码或加大线程的堆栈尺寸(Xss)。

内存优化最佳实践

Java内存优化主要是指对JVM的内存模型进行优化的过程,主要手段是通过JVM参数来调整JVM内存的运行时状态,通常JVM参数分为三大类:

  • 标准参数(-):所有的JVM实现都必须实现这些参数的功能,而且向后兼容;非标准参数(-X):所有的JVM实现都必须实现这些参数的功能,但不保证向后兼容;非Stable参数(-XX):此类参数各个JVM实现会有所不同,将来可能会随时取消,需要慎重使用;

下面我们将针对常见的涉及性能调优的JVM参数逐个进行讲解。

了解JVM的两种启动模式:调试模式和生产模式(-client -server):

  • 设置JVM使用client模式,特点是启动速度比较快,但运行时性能和内存管理效率不高,通常用于客户端应用程序或者PC应用开发和调试。设置JVM使server模式,特点是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境。在具有64位能力的Java环境下将默认启用生产模式,而忽略-client参数。

将堆内存的初始值与最大值设置为相同(-Xms -Xmx):

将堆内存的初始值与最大值设置为相同意味着禁用堆增长,通过前面学习的内容可以知道,每当发生一次堆增长时,至少会伴随两次的完全垃圾回收(前后各一次),如果一次增长不能满足要求时,情况会变的更糟。所以记住这一条,永远将堆内存的初始值与最大值设置为相同。

注意,当堆内存的初始值与最大值设置为相同时,-XX:MinHeapFreeRatio 和 -XX:MaxHeapFreeRatio 参数将失效。

合理的分配年青代与年老代的大小(-Xmn -XX:NewRatio -Xmn):

当使用Spring Ioc/AOP、Hibernate或其它的需要在系统中维持大量缓存对象的框架时,应当将年老代所占比例加大。通常来讲缓存对象会长期占用年老代,设置一个大的年老代可以有效的降低次级垃圾回收和完全垃圾回收的发生概率,JVM参数中没有直接设置年老代尺寸的参数,但可以通过减小年青代的尺寸来变相加大年老代,事实上现在流行的J2EE框架都大量使用缓存技术来提高系统性能,所以加大年老代的尺寸是一个通用的JVM调优方法,通过一个设置得当的内存参数加上优秀的架构作支撑,理论上可以100%避免次级垃圾回收和完全垃圾回收的发生。-Xmn是设置固定的年青代大小, -XX:NewRatio 是设置年青代在整个堆内存中占的比例;

当不使用前面提到的框架,很少或不使用缓存对象时,应当设置一个大的年青代,一个大的年青代带来的好处是降低初级垃圾回收的发生(只是降低,永远不要期望避免初级垃圾回收的发生),象基于JSP/JavaBean模式开发的小型WEB应用或通过精确控制的小型的Java桌面应用,可以考虑使用这种配置方案,事实上,系统80%以上的GC消耗都来自于次级垃圾回收和完全垃圾回收,减少次级垃圾回收和完全垃圾回收带来的性能提高要远远高于降低初级垃圾回收带来的效果。

根据项目规模适当的设置永久代的大小(-XX:PermSize -XX:MaxPermSize):

永久代被用来存储类和类的静态成员,当系统需要加载大量的类或在类中大量使用静态成员(静态方法或变量)时(工具类?),应设置一个大的永久代。事实上一个系统稳定运行一段时间后,永久代的大小是可以评估出来的(需要借助一些调优工具)。永久代设的过大其实对系统性能没有提升,反而因为过多的占用了堆空间而限制了年青代和年老代的大小,如果你的堆内存总量在1.5G,那么将永久代的尺寸设置为256M吧。

调整新生代与复活代的尺寸比例(-XX:SurvivorRatio):

这是一个高级的调优内容,确保除非确实需要,否则轻易不要使用这个参数。通过前面学习的内容我们知道,初级垃圾回收只发生在新生代溢出的情况下(只此一条),因此加大新生代在年青代中所占的比例可以更明显的降低初级垃圾回收的发生概率(试想一下,如果将整个堆空间全部设置为新生代会发生什么情况?)。 这么作带来的负效应是使复活代变的很小(回想一下复活代的作用),这样将导致复活带无法容纳足够多的“准死亡对象”从而造成大量本应该在初级垃圾回收中销毁的对象被迫提前进入到年老代中,最终的结果会导致次级垃圾回收的频繁发生而造成不必要的性能损耗。反之,如果将复活代所占的比例调大,那么准死亡对象的问题就不会发生了,但由于新生代太小,造成频繁的初级垃圾回收,对系统性能也是不利的。Sun hotspot JVM默认的新生代与复活代的比例为50%(由于存在活动复活代和非活动复活代两个大小一样的复活代,所以一个复活代占用年青代的比例为25%)。

设置一个合理的垃圾存活年龄(-XX:MaxTenuringThreshold):

这个参数网上很少被提到,其实它对系统性能的影响还是很大的。根据Sun的官方文档,这个参数用来设置Java对象在复活代内“熬”过几次初级垃圾回收后才会被移入年老代。当一个系统中存在比较多的“准缓存对象”时应该考虑将这个值设大。准缓存对象是这样一类对象,它会在内存中存在一段时间,但总会有新的缓存对象来替换它(频繁变化的数据库缓存?AA10?)或它的存在具有一定的时效性(一个繁忙的WEB系统的Session对象?Request?),那么为了尽可能的优化系统性能,我们应该让JVM在初级垃圾回收时就能够回收这些对象,而不应是次级垃圾回收。当然将这个值设的太大会导致一些真正的缓存对象长时间留在复活区内从而加重初级垃圾回收的压力,而且,当复活区溢出时,总是会将年龄最大的对象移动到年老区,不管你将这个值设的有多大,补充一点,将这个参数设置为0代表你要禁用复活区,系统默认值是15。

强制JVM在进行完全垃圾回收前先进行初级垃圾回收(-XX:+ScavengeBeforeFullGC):

望名知义,如果初级垃圾回收成功回收了足够的可用空间,就不用再进行完全垃圾回收了,但如果初级垃圾回收没有回收到足够的可用空间,则完全垃圾回收照样会进行,这时反而白白消耗了一次初级垃圾回收。

设置线程的堆栈大小(-Xss)

 
当且只当你开发的是一个“算法密集”型的系统(视频压缩解压缩软件)时,可以考虑加大堆栈尺寸。其它任何时候当看到“Stack Over Flow”异常时首先考虑你的代码是否出现的死循环。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

挑战极限性能:禁用垃圾回收器(-Xnoclassgc):

设置该参数后将禁用JVM使用任何垃圾回收器,禁用垃圾回器意味着系统性能将达到极限值,但后果是必须由我们自己来负责回收垃圾,不幸的是Java语言并没有提供给我们任何手动回收对象的方法。所以只有在一些极端的环境下才考虑使用这个参数来换取最高的系统性能,比如象JNDI这一类只会不断增加对象,而“绝对”不会出现垃圾的情况。

选择一个合适的垃圾回收器(-XX:UseParallelGC -XX:-UseConcMarkSweepGC -XX:-UseSerialGC):

Java5.0为我们提供了三种可用的垃圾回收器:串行回收器、并行回收器和并发回收器。串行回收器性能最差,但在单核处理器和小尺寸堆上会有意外表现。并行回收器具有最大回收速度,但在回收过程中会暂停应用程序。并发回收器速度较慢但却不会暂停程序(不暂停不代表不减慢)。Java5.0默认在年青代使用并行回收器以换取最大的吞吐量,在年老代使用并发收集器来减少对应用程序的暂停时间。在年青代永远使用并行回收器吧,因为初级回收几乎是在每时每刻发生,使用速度最快的并行回收器永远是你的最佳选择。如果你面对的是一个繁忙的系统,而频繁的年老代回收正在严重拖慢系统性能,这时考虑使用-XX:-UseParallelGC参数强制JVM在年老代使用并行收集器,此时快速的并行收集器会为你带来可观的性能提升。否则,使用系统默认的并发收集器吧。

跟踪JVM调试信息(-verbose:gc -verbose:class -Xprof -Xloggc:file):

  • -verbose:gc:输出每次GC的相关情况,输出形式:[GC 118250K->113543K(130112K), 0.0094143 secs] [Full GC 121376K- >10414K(130112K), 0.0650971 secs]。-verbose:class:输出JVM载入类的相关信息,当JVM报告说找不到类或者类冲突时可此进行诊断。-Xprof:打开JVM调试信息,跟踪正在运行的程序,并将跟踪数据在标准输出输出,适合于开发环境调试 。-Xloggc:file:与-verbose:gc功能类似,只是将每次GC事件的相关情况记录到一个文件中。

内存参数设计示例

java 
  -server 
  -XX:UseParallelGC 
  -Xprof -verbose:gc 
  -Xmx1550m 
  -Xms1550m 
  -Xss128k 
  -Xns512m 
  -XX:NewRatio=4 
  -XX:SurvivorRatio=4 
  -XX:MaxPermSize=256m 
  -XX:MaxTenuringThreshold=10 
  -XX:NewRatio=4
 
  • -server:使用产品模式启动JVM;-XX:UseParallelGC:在年老代使用并行回收器;-Xmx1550m Xms1550m:将堆的最小值与最大值设置为相同;-Xns512m:设置年轻代大小为512M。整个堆大小=年轻代+年老代+持久代。-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5;-XX:SurvivorRatio=4:设置年轻代中新生代与复活代的大小比值。设置为4,则两个复活代与一个新生代的比值为2:4,一个复活代占整个年轻代的1/6;-XX:MaxPermSize=128m:设置永久代大小为256M;-XX:MaxTenuringThreshold=10:设置垃圾最大年龄,对象在复活区内存活10次后被移动到年老区;-Xss128k:设置每个线程的堆栈大小为128K;-Xprof -verbose:gc:打开JVM调试信息,打开垃圾回收调试信息

JVM内存模型与性能调优的更多相关文章

  1. JVM内存模型及参数调优

    堆.栈.方法区概念区别 1.堆 堆内存用于存放由new创建的对象和数组.在堆中分配的内存,由java虚拟机自动垃圾回收器来管理.根据垃圾回收机制的不同, Java堆有可能拥有不同的结构,最为常见的就是 ...

  2. JVM的内存结构以及性能调优

    JVM的内存结构以及性能调优 发布时间: 2017-11-22 阅读数: 16675 JVM的内存结构以及性能调优1:JVM的结构主要包括三部分,堆,栈,非堆内存(方法区,驻留字符串)堆上面存储的是引 ...

  3. JVM内存模型和性能优化 转

    JVM内存模型和性能优化 JVM内存模型优点 内置基于内存的并发模型:      多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于 ...

  4. 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控

    如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...

  5. JVM | 第1部分:自动内存管理与性能调优《深入理解 Java 虚拟机》

    目录 前言 1. 自动内存管理 1.1 JVM运行时数据区 1.2 Java 内存结构 1.3 HotSpot 虚拟机创建对象 1.4 HotSpot 虚拟机的对象内存布局 1.5 访问对象 2. 垃 ...

  6. Java内存泄露及性能调优实例

    内存泄漏及解决方法 1)系统崩溃前的一些现象 每次垃圾回收的时间越来越长,由之前的10ms延长到50ms左右,FullGC的时间也有之前的0.5s延长到4.5s:FullGC的次数越来越多,最频繁时隔 ...

  7. 艾编程coding老师:深入JVM底层原理与性能调优

    1. Java内存模型JMM,内存泄漏及解决方法:2. JVM内存划分:New.Tenured.Perm:3. 垃圾回收算法:Serial算法.并行算法.并发算法:4. JVM性能调优,CPU负载不足 ...

  8. JVM常用命令和性能调优建议 [Could not create the Java virtual machine]

    一.查看jvm常用命令jinfo:可以输出并修改运行时的java 进程的opts. jps:与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号. ...

  9. JVM常用命令和性能调优建议

      一.查看jvm常用命令jinfo:可以输出并修改运行时的java 进程的opts. jps:与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程 ...

随机推荐

  1. Win10下SQLServer2000的安装

    Win10的技术预览版已经发布近两个星期了,我也迫不及待地装上尝鲜,发现SQLServer2000在Win10上无法安装,在翻遍网上资料和经过无数次尝试后得到了一种安装方法,希望能够帮助遇到类似问题的 ...

  2. HYPER V 文件共享 复制文件 共享硬盘 来宾服务

    虚拟机的设置   -->  集成服务 –> 来宾服务  勾选    文件就可以在本地机器和虚拟机上来回复制了. 他可让 Hyper-V 管理员在运行虚拟机的同时将文件复制到虚拟机,且无需使 ...

  3. 【Yii2-CookBook】JSON 和 XML 输出

    Web 和移动应用程序现在不仅仅只是用来呈现 HTML. 现在开发一个移动客户端,利用服务器 api 驱动前端,所有的用户交互都在客户端哪里.JSON 和 XML 格式通常用于序列化和传输结构化数据通 ...

  4. windows7 阻止copyfile到windows目录的解决办法

    一. windows7 x64,uac会阻止copyfile到c:/windows.提示拒绝访问. [会引起uac提示的3种情况: Administrator access token checks. ...

  5. javascript序列化和反序列化

    一. JavaScript中的对象序列化(Serialize)和反序列化(Deserialize),简单实例: var obj = {id: 1, name: 'yoyo', age: undefin ...

  6. 工程中建立多个src目录

    android 工程下可以有多个源代码的目录,不一定都要放到src下面.可以在 .classpath 文件中添加. 默认是这样的: <classpath> <classpathent ...

  7. 01shell入门基础

    01shell入门基础 为什么学习和使用shell编程 shell是一种脚本语言,脚本语言是相对于编译语言而言的.脚本语言不需要编译,由解释器读取程序并且执行其中的语句,而编译语言需要编译成可执行代码 ...

  8. sql查询单个银行账号重复

    非一单位多银行账号. 今天成都公司熊娇付款时候单位名称在弹出的网银补录变成1,从开户银行看都是正常的,只是在分子公司集团这边点击修改开户银行保存就提示错误“银行账号不能重复” select * fro ...

  9. Android学习笔记(十四)

    Android中的数据存储 数据持久化就是指那些内存中的瞬时数据保存到存储设备中.Android系统中主要提供了三种方式用于简单地实现 数据持久功能,即文件存储.SharedPreferences存储 ...

  10. dependencies 和 devDependencies

    npm install node_module –save自动更新dependencies字段值 npm install node_module –save-dev自动更新devDependencie ...