Chinaunix首页 | 论坛 | 博客
  • 博客访问: 113871
  • 博文数量: 5
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-28 13:31
文章分类

全部博文(5)

文章存档

2015年(1)

2013年(4)

我的朋友

分类: Java

2013-02-24 13:05:49

      小弟初来乍到,请各位大牛多指教和包涵。下面主要自己在学习关于JVM过程中,对JVM的内存使用,JVM中出现OOM,GC,JVM的常见工具等相关知识的理解和总结,现在分享给大家,希望对大家有所帮助,另外有一些理解有误的地方还请大牛们进行批评和指正!


一.名词解释:

    JVM:是Java Virtual Machine(Java)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java包括一套指令集、一组寄存器、一个栈、一个堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java上运行的),就可以在多种平台上不加修改地运行

    GC:是garbage collection(垃圾回收器),在java虚拟机中的一种内存回收机制,在编程时不需要java程序员对不必使用的变量进行释放回收,而是再JVM中实现自动的判断回收。在系统GC会根据不同的情况选择不同的回收算法。

   OOM:是Out Of Memory(内存溢出),表示在JVM中由于对内存使用不当,如对该释放的内存资源没有及时的释放,导致其一直不能被再次使用而使计算机内存被耗尽的现象。一般通过重启服务可以恢复。


二.java运行时的内存区域和OOM的原因:

    众所周知,程序在运行是,数据信息和业务逻辑都存放在内存中,java也不例外,java在运行时有多块内存使用区域,如程序计数器,虚拟机栈,方法区,java堆,运行常量池,直接内存使用等,同时在使用内存的过程中,可能会由于一些原因导致内存泄露或内存溢出的情况,下面我们讲述下java运行时的几个内存区域以及出现OOM的常见原因。

1.程序计数器:存放程序运行下一条指令需要的字节码指令,线程私有。无OOM。

2.虚拟机栈:存放方法的局部变量表,操作数栈,动态链接,方法出口等,局部变量表所需的内存空间在编译期就已经完成分配。一般是由于栈的深度太小或者栈的容量太小,若果开多个线程的话会更明显,-Xss(栈容量)

3.本地方法区:和虚拟机栈是为执行java方法服务类似,本地方法栈是为使用到的native方法服务。

4.java堆:存放所有对象实例的地方,存放大量的对象实例,属于线程共享。内存泄露或内存溢出,一般是通过不断的创建对象导致而没有进行清除导致,-Xmx(最大),-Xms(最小),-Xmn(不可扩展) -XX:HeapDumpOnOutOfMemoryError(出现OOM时会dump当前的内存堆快照)。

5.方法区:永久代,一般存放虚拟机加载的类信息,常量,静态变量,在编译期编译的代码等数据。回收一般是针对常量池的回收和对类型的卸载。一般是通过产生大量的类去填充方法区,导致其填满,出现OOM。

6.运行常量池:存放字面常量和符号引用,一般是通过string.intern()方法来分配一个常量字符串。-XX:PermSize,-XX:MaxPermSize来限定方法区的大小。

7.直接内存:基于通道和缓冲区的IO方式,可以使用Native函数库直接分配对外内存,然后通过一个存储在java堆里的DirectByteBuffer对象作为这块内存的应用进行操作。--XX:MaxDirectMemorySize(最大直接内存)来限制。


三.java中对象的访问:

1.通过句柄访问:表示JVM中的每一个对象都对应着一个句柄,然后将其放入到句柄池中,让要访问对象是,通过访问句柄能找到对应的每个对象的实际存放位置。

2.直接指针访问:表示JVM中的每一个对象直接对应着一个地址指针,当访问时,直接访问该地址,即可找到需要访问的对象。

判断对象的是否存活方法:

1.引用计数方式算法:和脚本语言python类似,每一个对象和变量都有一个引用计数,每次对该对象进行操作时,都会对其引用计数进行增减,只有当一个对象的引用计数为0时,才可以将该对象进行删除,并对该对象的内存区域进行回收。

2.根搜索算法:表示从一个GCRoot开始查找对象的对象,如果该对象到GCRoot中有一条链路(图),即该对象与GCRoot关联,表示该对象处于存活状态,如果该对象没有到GC的关联,则会将这个对象进行标记,然后对其确定是否需要进行内存回收。

作为GCRoot的条件:

1)java虚拟栈中引用的对象

2)方法区中的类静态属性引用的对象

3)方法区中常量引用的对象

4)本地方法中JNI的应用对象。

引用的分类:

1.强引用:Object obj=new Object(),垃圾收集器永远不会回收掉被引用的对象。

2.软引用:当系统将要出现内存溢出错误时,会将该对象放到回收区内进行第二次回收,如果回收后还是没有足够的内存,才会抛出内存溢出。

3.弱引用:对象只能生存到下一次垃圾收集发生之前。

4.虚引用:对象在回收时发一个系统通知。


四.JVM回收算法:

    在JVM中,在内存使用完后,在后续不再使用内存后,需要对可回收的内存进行回收,否则会出现内存泄露,下面介绍JVM的几种不同的内存回收算法。

1.标记-清除算法:表示将分配的内存区域中的各块进行标记(包括已分配,未分配,可回收等),定期对可回收的进行一次性进行回收。这种算法效率不高,但内存分片多。

2.复制算法:将内存区域分成相等两块,每一块有若干个小块,然后使用其中的一块,另一块作为该块的复制块,当其中一块分配完后,会将其中可以回收的内存进行回收。这种算法效率高,但内存使用率少,改进方法是可以采用一定的比例进行分配两块块的大小。

3.标记-整理算法:这种方式和标记-清除算法类似,但是在标记完后,会采用将占用内存进行挪动,形成内存的连续分配,效率也不高。

4.分代回收算法:进行不同代的划分,然后对不同代采用不同的回收算法。


五.垃圾收集器:

    如果说回收算法是JVM的内存回收原理,那么垃圾收集器就是JVM的内存回收实现。垃圾收集器主要是对不再使用的内存进行回收,以便为后续再次使用内存空间时有可用空间。下面主要介绍几种常见的垃圾收集器。

Sarial New:单线程,有停止工作线程等待  复制算法+标记整理

Pen New      多线程,并行,停止工作线程等待,复制算法+标记整理

Parallel Scavenge  多线程,并行,强调的是吞吐量,复制+标记整理,控制最大垃圾收集停顿时间:-XX:MaxGCPauseMillis,吞吐量大小-XX:GCTimeRatio

Sarial Old    和New一样,针对的是老年代的回收算法,标记整理

Para Old     和New一样,老年代的回收算法标记整理

CMS         并发,初始标记,并发标记,重新标记,并发清除,对CPU敏感,有浮动垃圾,有内存碎片

G1          分代回收,并有不同的优先级

注:上述的几种算法实现可以配合起来使用,但其中Parallel Scavenge不能和CRM一起配合使用。


六.内存分配:

1.对象分配优先在新生代: --XX:SurvivorRatio=8

2.大对象分配到老年代:-XX:PretenureSizeThreadold=3145728

3.长期存活的对象将进入到老年代:-XX:MaxTenuringThreshold=1

4.动态年龄判定:

5.空间分配担保:-XX:HandlePromotionFailure

对象在内存中的自救:对象在标记后,需要进行再次标记,并进行筛选,筛选的条件是是否有必要执行finalize(),没有覆盖到或已经执行的就没有必要,其他的需要,然后在需要执行finalize()的时候进行一次自救,就是和其他的对象进行关联。


七.常见的jvm的性能监控命令

    JVM的原理固然重要,但常常我们需要对JVM的状态信息和使用情况进行调试,下面介绍一些常见的JVM性能监控命令,希望对大家在日后遇到问题后进行定位时会有所帮助。

1.jps:显示JVM的进程的信息,jps -v|m|l|q

2.jstat:收集JVM各方面的运行数据,jstat -gc 2083 2000 20(每隔2秒监控一次,共做10),对JVM进行监控很有效和定位

3.jinfo:显示JVM的配置信息,可以通过其对JVM的配置信息进行修改,jinfo  $pid

4.jmap:生成JVM的内存的快照,pid=`ps uax |grep java|awk '{print $2}'`;kill -3 $pid;jmap -heap:format=b $pid //jmap -heap $pid,内存内的所有对象的情况。

5.jhat:分析heapdump的文件,让用户在浏览器上进行分析查看。

6.jstack:显示JVM的线程快照,jstack -l vmid,出现程序崩溃时,通过查看stack信息查看具体原因。



阅读(1218) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Linux中CRT终端的显示设置

给主人留下些什么吧!~~