标签:
1.程序计数器器:很小的一块内存空间,在java中线程是通过抢度的模式来使用cpu的内存空间的,因此每个线程都有一个独立的程序计数器空间,用来记录下一条要运行的指令操作,各个线程互不影响,存放的是指令的字节码的地址,如果是native方法的话,则计数器为空
2.java虚拟机栈:线程私有的空间,用来保存所属于该线程的局部变量,结果
3、本地方法栈:于java虚拟机栈类似用来保存属于native的方法锁拥有局部变量和结果
4、方法区:所有线程锁共享的,用来保存的信息是类的元数据,比如类的类型信息,常量池、域信息,方法信息、类的类型信息,比如类的完整名称、父类的名称、类型修饰符、常量池包括的是类方法中所拥有的常量的信息、方法信息包括的是方法名称、返回类型、方法参数、方法修饰符、方法字节码。总之,方法区内保持的信息,大部分都来自于.class文件,是java应用程序中必不可少的重要数据。
5.堆:分配对象的内存空间。
1、引用计数法
该对象有引用则计数器加1,失去引用的时候就减一,因此只要计数器为0,就证明该对象没有被引用该,就可以被回收。但是不能解决相互引用的问题
2、标记-清除算法
清除的时候分为两个阶段:先进行标记,然后开始清除的操作。标记的时候通过根节点开始标记所有被引用的对象,针对上述两个相互引用的对象的话,由于没有于根节点相关联,因此可以被清除掉的。但是通过这种链式标记的形式的话,回收的对象散落在不同的内存空间中,因此回产生很多的内存碎片,回收后的内存空间是不连续的。
3.复制算法
内存分为两份,用的时候用一份,清除的时候,将正在使用的空间复制到另一块,然后清除即可,重新标记当前为可使用的空间
但是也会有缺点,内存一分为二,系统内存折半,并且还需要复制,资源浪费
4、标记-压缩算法
前提是存活对象较少,垃圾对象较多的情况下,只不过在标记清除的基础上最后又将内存碎片进行了压缩的操作
5. 分代收集算法
分代收集算法是根据对象的存活周期的不同,将内存划分为几块。当前的商业虚拟机的垃圾收集都采用了该算法。一般把Java堆分成新生代(年轻代)和老年代(年老代)。这样就可以根据各年代中对象的存活周期来选择最合适的收集算法了。新生代,由于只有少量的对象能存活下来,所以选用“复制算法”,只需要付出少量存活对象的复制成本。老年代,由于对象的存活率高,没有额外的空间分担,就必须使用“标记-清除”或“标记-整理”算法。
上面说完算法后,下面来看一下垃圾收集器的类型都有哪些?
Serial收集器/serial Old收集器
是单线程的,使用复制算法,当它工作的时候,必须暂停其他所有的工作线程,特点是简单而高效,对于运行在Client模式下的虚拟机来说是一个很好的选择。
ParNew收集器
是Serial收集器的多线程版
Parallel Scavenge收集器/Parallel Old收集器
Parallel Scavenge收集器,也是使用复制算法的,并行的多线程收集器,它关注的是吞吐量,其他的收集器关注的是垃圾收集时用户线程的停顿时间。
CMS收集器
是一种以获取最短回收停顿时间为目标的收集器
G1收集器
基于标记整理算法,可以非常精确的控制停顿。
1.新生代串行收集器:单线程的模式,独占式的回收,使用的是复制算法,单线程的模式,没有线程的切换的开销,因此使用于cpu内存较小或者内存不是很充分的情况下
参数:-XX:+UseSerialGC
2.老年代串行:使用的是标记-压缩的算法
参数:
-XX:UseSerialGC:新生代和老年代都使用串行收集器
-XX:UseParNewGC:新生代使用并行收集器,老年代使用串行收集器
-XX:UseParallelGC:新生代使用并行回收收集器,老年代使用串行收集器
-XX:UseConcMarkSweepGC:新生代使用并行,老年代使用CMS
使用的JVM参数的配置信息
1.堆快照:-XX:+HeapDumpOnOutOfMemoryError and -XX:HeapDumpPath=c:\m.hprof
2.错误处理:-xx:OnOutOfMemoryError=c:\reset.bat
3. -Xloggc:${目录}/managed1_gc.log -XX:+HeapDumpOnOutOfMemoryError
首先通过看GC日志进行排查,gc的频率和次数。其次可以看dump堆的快照找到问题的所在,再结合一些工具,例如jprofiler来进行内存的跟踪,随时监视垃圾回收,线程允许的状况。
Jconsole,jProfile,VisualVM。 堆信息查看,线程监控,热点分析(CPU热点:检查系统哪些方法占用的大量CPU时间;内存热点:检查哪些对象在系统中数量最大(一定时间内存活对象和销毁对象一起统计),内存泄露的检查(内存泄漏一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而导致新的资源分配请求无法完成,引起系统错误。)
把那几个命令好好了解一下。调优的命令,好好记一下
http://blog.csdn.net/jiangguilong2000/article/details/17971247
详细的top命令请参考
http://www.cnblogs.com/ggjucheng/archive/2012/01/08/2316399.html
http://blog.csdn.net/feihong247/article/details/7874063
jstack:打印出给定的java进程ID,分析dump文件
JPS:列出所有的jvm的实例
dsta
首先通过TOP命令找到,所有线程对CPU占用的情况。然后通过jstack来对具体的线程进行具体的分析。
持久代用来防止类、类的一些常量操作
1.类和接口的全限定名
2、字段的名称和描述符
3、方法和名称和描述符
两个原则
1.一个是将转移到老年代的对象数量降到最少
因为老年代空间上的GC处理会花费更多的时间,减少被转移到老年代对象的数据可以显著地减少Full GC的频率。可以通过调整新生代空间的大小。
2、另一个是减少full GC的执行时间
FULL GC的执行时间要比Minor GC要长的多,因此如果full gc花费了太多的时间的话,一些连接可能会发生超时的错误。如果视图通过减少老年代空间来减少full GC执行的时间,可能会导致OutofMemoryError或者full gc执行的次数会增加。
是否需要进行gc优化
一般情况下,如果GC执行的时间只有0.1--0.3秒的话,就没必要浪费时间去进行GC优化,但是如果GC执行的时间在1秒或者2秒以上的话,GC将势在必行。一般下面情况下就不需要进行GC优化了
1.Minor GC执行的很快(小于50ms)
2.Minor GC执行的并不频繁(大概10秒一次吧)
3.Full GC执行的很快(小于1秒)
4.FULL GC执行的并不频繁(10分钟一次)
3.调整GC类型/内存空间
选择调整合适的GC类型和设定内存空间,针对性的优化
4.分析结果
调整了GC参数后,持续收集24小时日志,进行结果分析。如果幸运的话,就找到最适合系统的GC参数,反之就需要分析日志来检查内存是如何来分配的。然后需要不断的调整GC类型和内存空间大小找到最佳的参数
5.如何设定空间大小
一般老年代我建议设置为500M,也就是一次fullgc后,如果老年代剩余300M的话,这就是300M(程序占用)+500(老年代最小空间)+200M(空闲内存)
至于新生代和老年代之间的比例呢一般设置为1比1
代码优化
1、尽量在合适的地方使用单例
2、尽量避免随意使用静态变量
例如 A类里面有一个静态变量B,此时静态变量B的声明周期与类A同步,如果A不卸载的话,对象会常驻在内存,直到程序终止
3、尽力避免过多的创建java对象
例如在循环中new 对象,因为系统不仅需要花费时间来创建对象,而且还需要花费时间来进行垃圾回收
4、尽量使用final修饰符
首先final修饰符的类是不可派生的,并且java编译器会寻找机会内联所有的final方法,能够提高性能一半
5、尽量使用局部变量
调用方法时,参数传递的都是临时变量,保存在栈中,其他变量入静态变量 实例变量都在Heap中创建。速度较慢
6、慎用synchronized方法
7、尽量使用stringbuilder和stringbuffer
8、尽量不要使用finalize方法
9、尽量使用基本类型代替对象
10、单线程尽量使用hashmap、arraylist
11、尽量合理的创建hashmap,避免进行hash重构
12、尽量使用位移来代替A/B的操作。
标签:
原文地址:http://www.cnblogs.com/xingzc/p/5748965.html