`
高成锋
  • 浏览: 51197 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

JVM学习总结一

    博客分类:
  • java
阅读更多

1. JVM内存

 

如图所示,JVM主要包括两个子系统和两个组件。两个子系统分别是Class loader子系统和Execution engine(执行引擎) 子系统;两个组件分别是Runtime data area (运行时数据区域)组件和Native interface(本地接口)组件。
 
Class loader子系统的作用:根据给定的全限定名类名(如 java.lang.Object)来装载class文件的内容到 Runtime data area中的method area(方法区域)。Java程序员可以extends java.lang.ClassLoader类来写自己的Class loader。  
Execution engine子系统的作用:执行classes中的指令。任何JVM specification实现(JDK)的核心都是Execution engine,不同的JDK例如Sun 的JDK 和IBM的JDK好坏主要就取决于他们各自实现的Execution engine的好坏。
Native interface组件:与native libraries交互,是其它编程语言交互的接口。当调用native方法的时候,就进入了一个全新的并且不再受虚拟机限制的世界,所以也很容易出现JVM无法控制的native heap OutOfMemory。
Runtime Data Area组件:这就是我们常说的JVM的内存了。它主要分为五个部分——
1、Heap (堆):一个Java虚拟实例中只存在一个堆空间
2、Method Area(方法区域):被装载的class的信息存储在Method area的内存中。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件内容并把它传输到虚拟机中。
3、Java Stack(java的栈):虚拟机只会直接对Java stack执行两种操作:以帧为单位的压栈或出栈
4、Program Counter(程序计数器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的饿地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。  
5、Native method stack(本地方法栈):保存native方法进入区域的地址
以上五部分只有Heap 和Method Area是被所有线程的共享使用的;而Java stack, Program counter 和Native method stack是以线程为粒度的,每个线程独自拥有自己的部分。
了解JVM的系统结构,再来看看JVM内存回收问题了——
Sun的JVM Generational Collecting(垃圾回收)原理是这样的:把对象分为年青代(Young)、年老代(Tenured)、持久代(Perm),对不同生命周期的对象使用不同的算法。(基于对对象生命周期分析)


如上图所示,为Java堆中的各代分布。  
1. Young(年轻代)
年轻代分三个区。一个Eden区,两个Survivor区。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制年老区(Tenured。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。  
2. Tenured(年老代)
年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。  
3. Perm(持久代)
用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=进行设置。

举个例子:当在程序中生成对象时,正常对象会在年轻代中分配空间,如果是过大的对象也可能会直接在年老代生成(据观测在运行某程序时候每次会生成一个十兆的空间用收发消息,这部分内存就会直接在年老代分配)。年轻代在空间被分配完的时候就会发起内存回收,大部分内存会被回收,一部分幸存的内存会被拷贝至Survivor的from区,经过多次回收以后如果from区内存也分配完毕,就会也发生内存回收然后将剩余的对象拷贝至to区。等到to区也满的时候,就会再次发生内存回收然后把幸存的对象拷贝至年老区。

通常我们说的JVM内存回收总是在指堆内存回收,确实只有堆中的内容是动态申请分配的,所以以上对象的年轻代和年老代都是指的JVM的Heap空间,而持久代则是之前提到的Method Area,不属于Heap。

----------------------------------------------------JVM的内存分区-------------------------------------------

JAVAJVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method) 

 

堆区:

1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)

2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放数据

栈区:

1.每个线程包含一个栈区,栈中只保存原始类型数据和对象和对象引用(不是对象),对象都存放在堆区中

2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。

3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)

方法区:

1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的classstatic变量。

2.方法区中包含的都是在整个程序中永远唯一的元素,如classstatic变量。

 

-----------------------------------   JVM 运行状态常用指令--------------------------------------------

查看JVM 运行状态时的某些信息常用指令:

2. jstat

这个命令对于查看Jvm的堆栈信息很有用。能够查看eden,survivor,old,permheapcapacity,utility信息

对于查看系统是不是有能存泄漏以及参数设置是否合理有不错的意义

 

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

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ] 

 

vmid 可用jps -ml查看 

 

1.generalOption: 

 

-help Display help message. 

-version Display version information. 

-options Display list of statistics options. See the Output Options section below. 

 

2.outputOptions: 

class  

类加载器行为统计,Statistics on the behavior of the class loader. 

compiler JIT

编译器行为,Statistics of the behavior of the HotSpot Just-in-Time compiler. 

gc heap   

垃圾收集行为,Statistics of the behavior of the garbage collected heap. 

gccapacity 

各代区域容量统计,Statistics of the capacities of the generations and their corresponding spaces. 

gccause 

类似-gcutil,附上垃圾收集的原因。Summary of garbage collection statistics (same as -gcutil), with the cause of the last and current (if applicable) garbage collection events. 

gcnew 

新生代gc行为。Statistics of the behavior of the new generation. 

gcnewcapacity 

新生代容量统计。Statistics of the sizes of the new generations and its corresponding spaces. 

gcold 

老生代gc行为。Statistics of the behavior of the old and permanent generations. 

gcoldcapacity 

老生代容量统计。Statistics of the sizes of the old generation. 

gcpermcapacity 

永久代容量统计。Statistics of the sizes of the permanent generation. 

gcutil 

当前JVM垃圾收集描述。Summary of garbage collection statistics. 

printcompilation 

方法编译统计。HotSpot compilation method statistics.  

 

 

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ] 

jstat -op -t -h20 vmid ms/m 

 

-t 第一列附加启动以来的timestamp 

-h20 每打印20行时附加列头信息 

vmid  jvm进程id 

ms/m   打印时长间隔 

 

 

 

各选项输出列说明 

-gc Option 

 

examples: 

 

jstat -gc -h50 29617 3000 

每隔3000ms输出一次gc统计信息,且每隔50行输出一次列头信息 

S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   

9536.0 9152.0 544.0   0.0   68672.0  66932.0   174784.0   88186.1   53120.0 51319.9     36    0.902   1      0.139    1.041 

9536.0 9152.0 544.0   0.0   68672.0  66932.0   174784.0   88186.1   53120.0 51319.9     36    0.902   1      0.139    1.041 

 

Garbage-collected heap statistics  Column Description 

 

S0C  Current survivor space 0 capacity (KB). 当前Survivor 0容量  S0C

S1C  Current survivor space 1 capacity (KB). 当前Survivor 1容量  S1C

S0U  Survivor space 0 utilization (KB). 当前Survivor 0占用       S0U

S1U  Survivor space 1 utilization (KB). 当前Survivor 1占用       S1U

EC  Current eden space capacity (KB). 当前eden容量               EC

EU  Eden space utilization (KB). 当前eden占用   EU

OC  Current old space capacity (KB). 当前老区容量   OC

OU  Old space utilization (KB). 当前老区占用   OU

PC  Current permanent space capacity (KB). 当前永久代容量   PC

PU  Permanent space utilization (KB). 当前永久代占用   PU

YGC  Number of young generation GC Events. 年轻代GC累计次数      YGC

YGCT  Young generation garbage collection time. 年轻代GC耗时     YGCT

FGC  Number of full GC events. Full GC 累计次数    FGC

FGCT  Full garbage collection time. Full GC 累计耗时   FGCT

GCT  Total garbage collection time.  GC累计耗时   GCT

 

总堆:262144k 

新生代:98304K 

幸存012288k 

幸存112288k 

eden73728k 

老生代:163840k 

永久代初始:51200K 

永久代最大:65536K

 

PermGen space简介

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域OutOfMemoryError: PermGen space从表面上看就是内存溢出,解决方法也一定是加大内存。

说说为什么会内存益出:

1)这一部分用于存放ClassMeta的信息,Class在被 Load的时候被放入PermGen space区域,它和和存放InstanceHeap区域不同。

2GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APPLOAD很多CLASS的话,就很可能出现PermGen space错误。这种错误常见在web服务器对JSP进行pre compile的时候。

如果你的WEB APP下都用了大量的第三方jar,其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。

解决方法: 手动设置MaxPermSize大小

修改TOMCAT_HOME/bin/catalina.sh,在echo "Using CATALINA_BASE:   $CATALINA_BASE"上面加入以下行:

       JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128m

建议:将相同的第三方jar文件移置到tomcat/shared/lib目录下,这样可以减少jar 文档重复占用内存。

OutOfMemoryPermGen Space异常的处理和分析

Java程序员没有遇到过OutOfMemory简直就是不可能的事情!

可见在Java的世界中,太多的不确定因素导致Java运行程序直接崩溃,直接抛出OutOfMemory异常,而一旦遇到了这个问题,调查起来就非常的困难。在JDK 5.0以前,OutOfMemory只有这么一句话: java.lang.OutOfMemory Exception…基本上无从下手,无从分析。从JDK 5.0以后对OutOfMemory增加了许多的详细说明,为这个异常的分析提供了很大的便利。

这次遇到的问题就是会抛出OutOfMemory:PermGen Space的异常,这个异常非常有意思,根据【此文章】的描述,这是一个Sun JVMbug,从2003年开始,一只到现在都没有解决。而且提出来的解决方案是使用JRockitBug产生的原因已经找到,就是因为JVM在分配PermGen Space的时候出现了PermGen Space不足的情况,默认情况下 PermGen的大小为64M,在不换用JRockit的情况下,可以在启动JVM的时候添加一个参数: -XX: MaxPermSize= 128m| 256m| 512m

那么究竟什么是PermGen呢?

PermGen 原来是指Permanent Generation,本身是在Java的垃圾收集机制(GC)中产生的一个概念。Java的垃圾收集机制最早只是遍历所有的对象,如果发现某个对象没有被引用,则回收,这是在早期的Java 1.0Java 1.1的时候的GC规则。慢慢的,这样一种愚蠢的”GC算法成为了JVM性能的瓶颈,在拥有大量数据的Java应用程序中,GC的算法被高度强化,于是各种各样高效的JVM GC算法被发展了起来。从J2SE也就是Java 1.2开始,JVM引入了多种GC算法,其中一种用的非常多的就是Generational Collection,中文也叫做分代收集法

分代收集法摈弃了对所有对象的遍历,而是采用一些经验属性去避免额外的工作(While naive garbage collection examines every live object in the heap, generational collection exploits several empirically observed properties of most applications to avoid extra work)。其中导入了一个非常关键的概念:infant mortality (幼儿死亡率),这表示越是新生成的变量或者对象,越容易被收集。下面一张图表示了对象的生命周期,横轴表示的是测试到对象的生命周期,纵轴表示在一个指定的生命周期上被回收的对象数量。

 

可以看到,在使用了分代收集法以后,年轻一代的对象被收集的比例最高。并且在内存中的对象会按照不同的年龄来划分,当一个年龄段的对象满了以后,在这个年龄段上就会发生垃圾收集,从最年轻的一代开始,一直到永生代,在内存中,所有的对象可以划分为很多代,最后的一代永生代就是“Permanent Generation”,这里就是直接引出“Permanent Generation”概念的地方。具体可以参考下图:

 

根据前面所说的情况,在分代垃圾收集的情况下会产生Permanent Generation的概念,而这个分代垃圾收集法是并行收集和并发收集的基础,所以Permanent Generation会一直存在,那么这个Permanent Generation究竟是做什么用的呢?这里保存了JVM中所有对象的类信息,包括类的元数据,还有方法描述等等,所以这一代内存垃圾收集算法是不一样的,在Java大程序的情况下,尤其是J2EE 或者说Java EE的大型应用程序上,Permanent Generation的大小会直接限定能载入类的数量和大小。

【解决办法】就是设定JVM启动的时候参数,可以如下设置:

java -XX: PermSize=64m -XX: MaxPermSize=128m

另外PermSize MaxPermSize如果设置为相同还可以在一定程度上提高性能,因为,PermSize在不断的变化中会需要转移其中的数据。如果固定了以后,则可以减少每次扩大PermSize带来的性能损失。

 

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

3. jstack

这个是用来查看jvm当前的thread dump的。可以看到当前Jvm里面的线程状况。

这个对于查找blocked线程比较有意义

 

jstack - Stack Trace 

为指定的线程输出 java 的线程堆栈信息,包括了进程里的所有线程。每一个线程 frame ,包括类全名,方法名,代码行。 

 

java.lang.Thread.State : RUNNABLE BLOCKED TIMED_WATTING(sleep 后会进入这种状态 (如果是 BLOCKED 状态就要注意了,看看 blocked 的状态在等待什么?因为什么而阻塞?)最常见的情况是线程在等待网络的读写,比如当网络数据没有准备好读时,线程处于这种等待状态,而一旦有数据准备好读之后,线程会重新激活,读取并处理数据。 

 

 

在线程中,有一些 JVM 内部的后台线程,来执行譬如垃圾回收,或者低内存的检测等等任务,这些线程往往在 JVM 初始化的时候就存在,如下所示: 

"Low Memory Detector" daemon prio=10 tid=0x081465f8 nid=0x7 runnable [0x00000000..0x00000000] 

"CompilerThread0" daemon prio=10 tid=0x08143c58 nid=0x6 waiting on condition [0x00000000..0xfb5fd798] 

"Signal Dispatcher" daemon prio=10 tid=0x08142f08 nid=0x5 waiting on condition [0x00000000..0x00000000] 

"Finalizer" daemon prio=10 tid=0x08137ca0 nid=0x4 in Object.wait() [0xfbeed000..0xfbeeddb8] 

 

jstack pid

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

分享到:
评论

相关推荐

    jvm自己学习总结

    jvm自己学习总结,对JVM的工作原理进行记录学习笔记

    JVM学习资料+笔记

    买的JVM学习资料(深入JVM内核—原理、诊断与优化),给大家分享还有自己整理的学习笔记

    JVM学习总结

    1.多进程,同时打开word,excel,ppt 2.多进程,迅雷同时下载多个资源 3.并发Concurrency,一个cpu在多个线程之间复用。所有并发处理都会经历排 队等候,唤醒,执行等步骤。微观上排队,宏观上同时! 4.并行...

    jvm的基础知识总结

    jvm的基础知识总结,根据线程共享和线程私有来划分,进行分别描述和具体参数解释和设置,可以更好的学习jvm的基础知识,方便以后运用

    个人总结之—JVM性能调优实战

    从实践中不断总结摸索的JVM调优经典之作,希望能给广大网友带来帮助!

    JVM入门实战/arthas实战/垃圾回收算法/垃圾回收器/jvm内存模型分析

    第一节:学习JVM的意义和目标 1.1 意义: 1.2 目标: 第二节:JVM内存模型 1.1 概念 1.2 JVM内存模型 1.3 Heap堆内存模型 第三节:定位垃圾对象的依据 1.1 引用计数法 1.2 可达性算法 第四节:垃圾回收算法 ...

    个人对JVM总结图.png

    个人对JVM的总结图。包括JVM的五部分(Program Counter Register、JVM Stack、Native Method Stack、heap、method area)。欢迎各位网友指正错误,互相学习讨论

    学习总结 包括Java JVM MySQL NoSQL UML 缓存 消息 分布式事务-StudySummary.zip

    学习总结 包括Java JVM MySQL NoSQL UML 缓存 消息 分布式事务-StudySummary

    jvm指令手册 +JVM必知必会,掌握虚拟机编译过程.rar

    《JVM必知必会》记录了对JVM的总结及学习笔记,详解的介绍了什么是jvm,以及弄清楚jvm的工作原理等等,会深入了解JVM有一定的帮助。 Java Virtual Machine(Java虚拟机),它bai是一个虚构出来du的计算机,是通过在...

    JVM的学习.pdf

    Jvm知识的基础详细学习笔记,总结了Jvm知识的各个知识点,可以用来复习以及对基础知识的巩固,对新人的学习很有帮助。

    学习总结 包括Java JVM MySQL NoSQL UML 缓存 消息 分布式事务 SOA 微服务 敏捷 架构设.zip

    学习总结 包括Java JVM MySQL NoSQL UML 缓存 消息 分布式事务 SOA 微服务 敏捷 架构设

    MySQL、JVM、RocketMQ、JUC、设计模式、数据结构与算法学习总结.zip

    MySQL、JVM、RocketMQ、JUC、设计模式、数据结构与算法学习总结

    jvm中的堆.xmind

    自己总结的jvm中堆的笔记,绘制了详细的思维导图,每个思维导图中均有详细的博文解释,方便大家学习和理解,免费分享给大家。适合jvm的爱好者和学习者

    JVM、GC详解及调优.pdf

    本文档详细讲解了JVM(Java Visual Mathine)的方方面面,首先由java的特性来描绘JVM的大致应用,再详细阐释了 JVM 的原理及内存管理机制和调优,讲述了与JVM密切...本文内容是对网络内容的总结,是学习 JVM 的好资料。

    jvm内存溢出

    jvm内存溢出 学习笔记

    jvm调优思维脑图

    总结了学习jvm调优的知识点,便于大家随时查看,快速串联思维。主要包括:java内存结构、堆内存的构成、堆内存参数调整、垃圾收集算法、垃圾收集器选择、JVM参数、java对象的内存分配过程、Tomcat调优并使用Jmeter...

    jvm方法区.xmind

    自己总结的jvm中方法区的笔记,绘制了详细的思维导图,每个思维导图中均有详细的博文解释,方便大家学习和理解,免费分享给大家。适合jvm的爱好者和学习者

    最全面的JVM优化经验总结

    主要介绍了最全面的JVM优化经验总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,,需要的朋友可以参考下

    Jvm内存面试问题总结(2020).docx

    自己在学习和面试过程中总结的一些常见面试题 , 包含了java内存模型 , java8以后内存变化. 垃圾回收算法, 常见的垃圾回收器 , G1垃圾回收器的优化 堆外内存如何使用等. 希望和大家共同进步 . 祝拿到满意的...

    JVM垃圾回收机制.xmind

    自己学习总结JVM垃圾回收机制的结构图,一起分享!!!

Global site tag (gtag.js) - Google Analytics